forked from extern/nushell
Compare commits
62 Commits
Author | SHA1 | Date | |
---|---|---|---|
2b06ce27d3 | |||
72c241348b | |||
ab2d2db987 | |||
07e05ef183 | |||
a986de8ad0 | |||
22cfe4391e | |||
97d17311f4 | |||
0f6fd30619 | |||
e1ebd461d2 | |||
f000d5d0a1 | |||
574c5961c8 | |||
69708f7244 | |||
62c5df5fc6 | |||
92c855a412 | |||
d395816929 | |||
5e34ef6dff | |||
d567c58cc1 | |||
4e0d7bc77c | |||
32581497ef | |||
d6df367c6b | |||
4e6327de1d | |||
b3d8666db0 | |||
1de7c3d033 | |||
962b258cc6 | |||
59697cab63 | |||
349af05da8 | |||
b3b3cf0689 | |||
5d59234f8d | |||
4f7b423f36 | |||
f7043bf690 | |||
1297499d7a | |||
bd0baa961c | |||
4ee536f044 | |||
8581bec891 | |||
8bcbc8eeb3 | |||
c164ef5489 | |||
cc3653cfd9 | |||
7fc65067cf | |||
f9ae882012 | |||
1d80a68f4c | |||
fda69354db | |||
cc5c4d38bb | |||
0fa0c25fb3 | |||
55eafadf02 | |||
51c74eebd0 | |||
ae9f4135c0 | |||
4e2d3ceaaf | |||
c9c6bd4836 | |||
d90420ac4c | |||
260ff99710 | |||
08014c6a98 | |||
66cedf0b3a | |||
707a4ebc15 | |||
d95375d494 | |||
1c1c58e802 | |||
7fe05b8296 | |||
17ef531905 | |||
b8e2bdd6b1 | |||
88817a8f10 | |||
3e8ce43dcb | |||
9d8845d7ad | |||
52578ba483 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -38,7 +38,7 @@ body:
|
||||
id: config
|
||||
attributes:
|
||||
label: Configuration
|
||||
description: "Please run `> version | pivot` and paste the output to show OS, features, etc"
|
||||
description: "Please run `> version | pivot key value | to md` and paste the output to show OS, features, etc"
|
||||
placeholder: |
|
||||
> version | pivot key value | to md
|
||||
╭───┬────────────────────┬───────────────────────────────────────────────────────────────────────╮
|
||||
|
5
.github/workflows/stale.yml
vendored
5
.github/workflows/stale.yml
vendored
@ -19,11 +19,12 @@ jobs:
|
||||
operations-per-run: 520
|
||||
enable-statistics: true
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'This issue is being marked stale because it has been open for 90 days without activity. If you feel that this is in error, please comment below and we will keep it marked as active.'
|
||||
stale-pr-message: 'This PR is being marked stale because it has been open for 45 days without activity. If this PR is still active, please comment below and we will keep it marked as active.'
|
||||
stale-issue-message: 'This issue is being marked stale because it has been open for 90 days without activity. If you feel that this is in error, please comment below and we will keep it marked as active. Otherwise, it will be closed in 10 days.'
|
||||
stale-pr-message: 'This PR is being marked stale because it has been open for 45 days without activity. If this PR is still active, please comment below and we will keep it marked as active. Otherwise, it will be closed in 10 days.'
|
||||
close-issue-message: 'This issue has been marked stale for more than 10 days without activity. Closing this issue, but if you find that the issue is still valid, please reopen.'
|
||||
close-pr-message: 'This PR has been marked stale for more than 10 days without activity. Closing this PR, but if you are still working on it, please reopen.'
|
||||
days-before-issue-stale: 90
|
||||
days-before-pr-stale: 45
|
||||
days-before-issue-close: 10
|
||||
days-before-pr-close: 10
|
||||
exempt-issue-labels: 'exempt,keep'
|
||||
|
2
.gitpod.Dockerfile
vendored
2
.gitpod.Dockerfile
vendored
@ -2,7 +2,7 @@ FROM gitpod/workspace-full
|
||||
|
||||
# Gitpod will not rebuild Nushell's dev image unless *some* change is made to this Dockerfile.
|
||||
# To force a rebuild, simply increase this counter:
|
||||
ENV TRIGGER_REBUILD 1
|
||||
ENV TRIGGER_REBUILD 2
|
||||
|
||||
USER gitpod
|
||||
|
||||
|
2720
Cargo.lock
generated
2720
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
101
Cargo.toml
101
Cargo.toml
@ -10,7 +10,7 @@ license = "MIT"
|
||||
name = "nu"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
version = "0.36.0"
|
||||
version = "0.39.0"
|
||||
|
||||
[workspace]
|
||||
members = ["crates/*/"]
|
||||
@ -18,38 +18,34 @@ members = ["crates/*/"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { version = "0.36.0", path="./crates/nu-cli", default-features=false }
|
||||
nu-command = { version = "0.36.0", path="./crates/nu-command" }
|
||||
nu-completion = { version = "0.36.0", path="./crates/nu-completion" }
|
||||
nu-data = { version = "0.36.0", path="./crates/nu-data" }
|
||||
nu-engine = { version = "0.36.0", path="./crates/nu-engine" }
|
||||
nu-errors = { version = "0.36.0", path="./crates/nu-errors" }
|
||||
nu-parser = { version = "0.36.0", path="./crates/nu-parser" }
|
||||
nu-path = { version = "0.36.0", path="./crates/nu-path" }
|
||||
nu-plugin = { version = "0.36.0", path="./crates/nu-plugin" }
|
||||
nu-protocol = { version = "0.36.0", path="./crates/nu-protocol" }
|
||||
nu-source = { version = "0.36.0", path="./crates/nu-source" }
|
||||
nu-value-ext = { version = "0.36.0", path="./crates/nu-value-ext" }
|
||||
nu-cli = { version = "0.39.0", path="./crates/nu-cli", default-features=false }
|
||||
nu-command = { version = "0.39.0", path="./crates/nu-command" }
|
||||
nu-completion = { version = "0.39.0", path="./crates/nu-completion" }
|
||||
nu-data = { version = "0.39.0", path="./crates/nu-data" }
|
||||
nu-engine = { version = "0.39.0", path="./crates/nu-engine" }
|
||||
nu-errors = { version = "0.39.0", path="./crates/nu-errors" }
|
||||
nu-parser = { version = "0.39.0", path="./crates/nu-parser" }
|
||||
nu-path = { version = "0.39.0", path="./crates/nu-path" }
|
||||
nu-plugin = { version = "0.39.0", path="./crates/nu-plugin" }
|
||||
nu-protocol = { version = "0.39.0", path="./crates/nu-protocol" }
|
||||
nu-source = { version = "0.39.0", path="./crates/nu-source" }
|
||||
nu-value-ext = { version = "0.39.0", path="./crates/nu-value-ext" }
|
||||
|
||||
nu_plugin_binaryview = { version = "0.36.0", path="./crates/nu_plugin_binaryview", optional=true }
|
||||
nu_plugin_chart = { version = "0.36.0", path="./crates/nu_plugin_chart", optional=true }
|
||||
nu_plugin_fetch = { version = "0.36.0", path="./crates/nu_plugin_fetch", optional=true }
|
||||
nu_plugin_from_bson = { version = "0.36.0", path="./crates/nu_plugin_from_bson", optional=true }
|
||||
nu_plugin_from_sqlite = { version = "0.36.0", path="./crates/nu_plugin_from_sqlite", optional=true }
|
||||
nu_plugin_inc = { version = "0.36.0", path="./crates/nu_plugin_inc", optional=true }
|
||||
nu_plugin_match = { version = "0.36.0", path="./crates/nu_plugin_match", optional=true }
|
||||
nu_plugin_post = { version = "0.36.0", path="./crates/nu_plugin_post", optional=true }
|
||||
nu_plugin_ps = { version = "0.36.0", path="./crates/nu_plugin_ps", optional=true }
|
||||
nu_plugin_query_json = { version = "0.36.0", path="./crates/nu_plugin_query_json", optional=true }
|
||||
nu_plugin_s3 = { version = "0.36.0", path="./crates/nu_plugin_s3", optional=true }
|
||||
nu_plugin_selector = { version = "0.36.0", path="./crates/nu_plugin_selector", optional=true }
|
||||
nu_plugin_start = { version = "0.36.0", path="./crates/nu_plugin_start", optional=true }
|
||||
nu_plugin_sys = { version = "0.36.0", path="./crates/nu_plugin_sys", optional=true }
|
||||
nu_plugin_textview = { version = "0.36.0", path="./crates/nu_plugin_textview", optional=true }
|
||||
nu_plugin_to_bson = { version = "0.36.0", path="./crates/nu_plugin_to_bson", optional=true }
|
||||
nu_plugin_to_sqlite = { version = "0.36.0", path="./crates/nu_plugin_to_sqlite", optional=true }
|
||||
nu_plugin_tree = { version = "0.36.0", path="./crates/nu_plugin_tree", optional=true }
|
||||
nu_plugin_xpath = { version = "0.36.0", path="./crates/nu_plugin_xpath", optional=true }
|
||||
nu_plugin_binaryview = { version = "0.39.0", path="./crates/nu_plugin_binaryview", optional=true }
|
||||
nu_plugin_chart = { version = "0.39.0", path="./crates/nu_plugin_chart", optional=true }
|
||||
nu_plugin_from_bson = { version = "0.39.0", path="./crates/nu_plugin_from_bson", optional=true }
|
||||
nu_plugin_from_sqlite = { version = "0.39.0", path="./crates/nu_plugin_from_sqlite", optional=true }
|
||||
nu_plugin_inc = { version = "0.39.0", path="./crates/nu_plugin_inc", optional=true }
|
||||
nu_plugin_match = { version = "0.39.0", path="./crates/nu_plugin_match", optional=true }
|
||||
nu_plugin_query_json = { version = "0.39.0", path="./crates/nu_plugin_query_json", optional=true }
|
||||
nu_plugin_s3 = { version = "0.39.0", path="./crates/nu_plugin_s3", optional=true }
|
||||
nu_plugin_selector = { version = "0.39.0", path="./crates/nu_plugin_selector", optional=true }
|
||||
nu_plugin_start = { version = "0.39.0", path="./crates/nu_plugin_start", optional=true }
|
||||
nu_plugin_textview = { version = "0.39.0", path="./crates/nu_plugin_textview", optional=true }
|
||||
nu_plugin_to_bson = { version = "0.39.0", path="./crates/nu_plugin_to_bson", optional=true }
|
||||
nu_plugin_to_sqlite = { version = "0.39.0", path="./crates/nu_plugin_to_sqlite", optional=true }
|
||||
nu_plugin_tree = { version = "0.39.0", path="./crates/nu_plugin_tree", optional=true }
|
||||
nu_plugin_xpath = { version = "0.39.0", path="./crates/nu_plugin_xpath", optional=true }
|
||||
|
||||
# Required to bootstrap the main binary
|
||||
ctrlc = { version="3.1.7", optional=true }
|
||||
@ -57,8 +53,7 @@ futures = { version="0.3.12", features=["compat", "io-compat"] }
|
||||
itertools = "0.10.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { version = "0.36.0", path="./crates/nu-test-support" }
|
||||
dunce = "1.0.1"
|
||||
nu-test-support = { version = "0.39.0", path="./crates/nu-test-support" }
|
||||
serial_test = "0.5.1"
|
||||
hamcrest2 = "0.3.0"
|
||||
rstest = "0.10.0"
|
||||
@ -66,6 +61,8 @@ rstest = "0.10.0"
|
||||
[build-dependencies]
|
||||
|
||||
[features]
|
||||
fetch-support = ["nu-command/fetch", "nu-command/post"]
|
||||
sys-support = ["nu-command/sys", "nu-command/ps"]
|
||||
ctrlc-support = ["nu-cli/ctrlc", "nu-command/ctrlc"]
|
||||
rustyline-support = ["nu-cli/rustyline-support", "nu-command/rustyline-support"]
|
||||
term-support = ["nu-command/term"]
|
||||
@ -74,15 +71,13 @@ which-support = ["nu-command/which", "nu-engine/which"]
|
||||
|
||||
default = [
|
||||
"nu-cli/shadow-rs",
|
||||
"sys",
|
||||
"ps",
|
||||
"sys-support",
|
||||
"ctrlc-support",
|
||||
"which-support",
|
||||
"term-support",
|
||||
"rustyline-support",
|
||||
"match",
|
||||
"post",
|
||||
"fetch",
|
||||
"fetch-support",
|
||||
"zip-support",
|
||||
"dataframe",
|
||||
]
|
||||
@ -110,12 +105,8 @@ extra = [
|
||||
wasi = ["inc", "match", "match", "tree", "rustyline-support"]
|
||||
|
||||
# Stable (Default)
|
||||
fetch = ["nu_plugin_fetch"]
|
||||
inc = ["nu_plugin_inc"]
|
||||
match = ["nu_plugin_match"]
|
||||
post = ["nu_plugin_post"]
|
||||
ps = ["nu_plugin_ps"]
|
||||
sys = ["nu_plugin_sys"]
|
||||
textview = ["nu_plugin_textview"]
|
||||
|
||||
# Extra
|
||||
@ -136,9 +127,6 @@ tree = ["nu_plugin_tree"]
|
||||
xpath = ["nu_plugin_xpath"]
|
||||
zip-support = ["nu-command/zip"]
|
||||
|
||||
#This is disabled in extra for now
|
||||
table-pager = ["nu-command/table-pager"]
|
||||
|
||||
#dataframe feature for nushell
|
||||
dataframe = [
|
||||
"nu-engine/dataframe",
|
||||
@ -146,12 +134,11 @@ dataframe = [
|
||||
"nu-command/dataframe",
|
||||
"nu-value-ext/dataframe",
|
||||
"nu-data/dataframe",
|
||||
"nu_plugin_post/dataframe",
|
||||
"nu_plugin_to_bson/dataframe",
|
||||
]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize for size.
|
||||
opt-level = "s" # Optimize for size.
|
||||
|
||||
# Core plugins that ship with `cargo install nu` by default
|
||||
# Currently, Cargo limits us to installing only one binary
|
||||
@ -166,31 +153,11 @@ name = "nu_plugin_core_inc"
|
||||
path = "src/plugins/nu_plugin_core_inc.rs"
|
||||
required-features = ["inc"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_ps"
|
||||
path = "src/plugins/nu_plugin_core_ps.rs"
|
||||
required-features = ["ps"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_sys"
|
||||
path = "src/plugins/nu_plugin_core_sys.rs"
|
||||
required-features = ["sys"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_fetch"
|
||||
path = "src/plugins/nu_plugin_core_fetch.rs"
|
||||
required-features = ["fetch"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_match"
|
||||
path = "src/plugins/nu_plugin_core_match.rs"
|
||||
required-features = ["match"]
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_core_post"
|
||||
path = "src/plugins/nu_plugin_core_post.rs"
|
||||
required-features = ["post"]
|
||||
|
||||
# Extra plugins
|
||||
|
||||
[[bin]]
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 - 2021 Yehuda Katz, Jonathan Turner
|
||||
Copyright (c) 2019 - 2021 Nushell Project
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
47
README.md
47
README.md
@ -76,53 +76,6 @@ You can also build Nu yourself with all the bells and whistles (be sure to have
|
||||
```shell
|
||||
cargo build --workspace --features=extra
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
#### Quickstart
|
||||
|
||||
Want to try Nu right away? Execute the following to get started.
|
||||
|
||||
```shell
|
||||
docker run -it quay.io/nushell/nu:latest
|
||||
```
|
||||
|
||||
#### Guide
|
||||
|
||||
If you want to pull a pre-built container, you can browse tags for the [nushell organization](https://quay.io/organization/nushell)
|
||||
on Quay.io. Pulling a container would come down to:
|
||||
|
||||
```shell
|
||||
docker pull quay.io/nushell/nu
|
||||
docker pull quay.io/nushell/nu-base
|
||||
```
|
||||
|
||||
Both "nu-base" and "nu" provide the nu binary, however, nu-base also includes the source code at `/code`
|
||||
in the container and all dependencies.
|
||||
|
||||
Optionally, you can also build the containers locally using the [dockerfiles provided](docker):
|
||||
To build the base image:
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile.nu-base -t nushell/nu-base .
|
||||
```
|
||||
|
||||
And then to build the smaller container (using a Multistage build):
|
||||
|
||||
```shell
|
||||
docker build -f docker/Dockerfile -t nushell/nu .
|
||||
```
|
||||
|
||||
Either way, you can run either container as follows:
|
||||
|
||||
```shell
|
||||
docker run -it nushell/nu-base
|
||||
docker run -it nushell/nu
|
||||
/> exit
|
||||
```
|
||||
|
||||
The second container is a bit smaller if the size is important to you.
|
||||
|
||||
### Packaging status
|
||||
|
||||
[](https://repology.org/project/nushell/versions)
|
||||
|
@ -9,7 +9,7 @@ description = "Library for ANSI terminal colors and styles (bold, underline)"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-ansi-term"
|
||||
version = "0.36.0"
|
||||
version = "0.39.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
@ -21,7 +21,6 @@ derive_serde_style = ["serde"]
|
||||
[dependencies]
|
||||
overload = "0.1.1"
|
||||
serde = { version="1.0.90", features=["derive"], optional=true }
|
||||
itertools = "0.10.0"
|
||||
|
||||
# [dependencies.serde]
|
||||
# version = "1.0.90"
|
||||
|
@ -93,7 +93,7 @@ pub static RESET: &str = "\x1B[0m";
|
||||
|
||||
impl Color {
|
||||
fn write_foreground_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
|
||||
match *self {
|
||||
match self {
|
||||
Color::Black => write!(f, "30"),
|
||||
Color::Red => write!(f, "31"),
|
||||
Color::Green => write!(f, "32"),
|
||||
@ -103,8 +103,8 @@ impl Color {
|
||||
Color::Magenta => write!(f, "35"),
|
||||
Color::Cyan => write!(f, "36"),
|
||||
Color::White => write!(f, "37"),
|
||||
Color::Fixed(num) => write!(f, "38;5;{}", &num),
|
||||
Color::Rgb(r, g, b) => write!(f, "38;2;{};{};{}", &r, &g, &b),
|
||||
Color::Fixed(num) => write!(f, "38;5;{}", num),
|
||||
Color::Rgb(r, g, b) => write!(f, "38;2;{};{};{}", r, g, b),
|
||||
Color::DarkGray => write!(f, "90"),
|
||||
Color::LightRed => write!(f, "91"),
|
||||
Color::LightGreen => write!(f, "92"),
|
||||
@ -118,7 +118,7 @@ impl Color {
|
||||
}
|
||||
|
||||
fn write_background_code<W: AnyWrite + ?Sized>(&self, f: &mut W) -> Result<(), W::Error> {
|
||||
match *self {
|
||||
match self {
|
||||
Color::Black => write!(f, "40"),
|
||||
Color::Red => write!(f, "41"),
|
||||
Color::Green => write!(f, "42"),
|
||||
@ -128,8 +128,8 @@ impl Color {
|
||||
Color::Magenta => write!(f, "45"),
|
||||
Color::Cyan => write!(f, "46"),
|
||||
Color::White => write!(f, "47"),
|
||||
Color::Fixed(num) => write!(f, "48;5;{}", &num),
|
||||
Color::Rgb(r, g, b) => write!(f, "48;2;{};{};{}", &r, &g, &b),
|
||||
Color::Fixed(num) => write!(f, "48;5;{}", num),
|
||||
Color::Rgb(r, g, b) => write!(f, "48;2;{};{};{}", r, g, b),
|
||||
Color::DarkGray => write!(f, "100"),
|
||||
Color::LightRed => write!(f, "101"),
|
||||
Color::LightGreen => write!(f, "102"),
|
||||
|
@ -297,7 +297,7 @@ mod tests {
|
||||
fn no_control_codes_for_plain() {
|
||||
let one = Style::default().paint("one");
|
||||
let two = Style::default().paint("two");
|
||||
let output = format!("{}", AnsiStrings(&[one, two]));
|
||||
assert_eq!(&*output, "onetwo");
|
||||
let output = AnsiStrings(&[one, two]).to_string();
|
||||
assert_eq!(output, "onetwo");
|
||||
}
|
||||
}
|
||||
|
@ -602,14 +602,14 @@ mod serde_json_tests {
|
||||
|
||||
#[test]
|
||||
fn color_deserialization() {
|
||||
let colors = &[
|
||||
let colors = [
|
||||
Color::Red,
|
||||
Color::Blue,
|
||||
Color::Rgb(123, 123, 123),
|
||||
Color::Fixed(255),
|
||||
];
|
||||
|
||||
for color in colors.iter() {
|
||||
for color in colors {
|
||||
let serialized = serde_json::to_string(&color).unwrap();
|
||||
let deserialized: Color = serde_json::from_str(&serialized).unwrap();
|
||||
|
||||
|
@ -75,6 +75,6 @@ mod test {
|
||||
assert_eq!(unstyled_len(&a), 18);
|
||||
|
||||
let l2 = [Black.paint("st"), Red.paint("-second"), White.paint("-t")];
|
||||
assert_eq!(sub_string(3, 11, &a).as_slice(), &l2);
|
||||
assert_eq!(sub_string(3, 11, &a), l2);
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,24 @@ description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.36.0"
|
||||
version = "0.39.0"
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-completion = { version = "0.36.0", path="../nu-completion" }
|
||||
nu-command = { version = "0.36.0", path="../nu-command" }
|
||||
nu-data = { version = "0.36.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.36.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.36.0", path="../nu-errors" }
|
||||
nu-parser = { version = "0.36.0", path="../nu-parser" }
|
||||
nu-protocol = { version = "0.36.0", path="../nu-protocol" }
|
||||
nu-source = { version = "0.36.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.36.0", path="../nu-stream" }
|
||||
nu-ansi-term = { version = "0.36.0", path="../nu-ansi-term" }
|
||||
nu-completion = { version = "0.39.0", path="../nu-completion" }
|
||||
nu-command = { version = "0.39.0", path="../nu-command" }
|
||||
nu-data = { version = "0.39.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.39.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.39.0", path="../nu-errors" }
|
||||
nu-parser = { version = "0.39.0", path="../nu-parser" }
|
||||
nu-protocol = { version = "0.39.0", path="../nu-protocol" }
|
||||
nu-source = { version = "0.39.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.39.0", path="../nu-stream" }
|
||||
nu-ansi-term = { version = "0.39.0", path="../nu-ansi-term" }
|
||||
nu-path = { version = "0.39.0", path="../nu-path" }
|
||||
|
||||
indexmap ="1.6.1"
|
||||
log = "0.4.14"
|
||||
|
@ -508,14 +508,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn can_use_loglevels() -> Result<(), ShellError> {
|
||||
for level in &["error", "warn", "info", "debug", "trace"] {
|
||||
for level in ["error", "warn", "info", "debug", "trace"] {
|
||||
let ui = cli_app();
|
||||
let args = format!("nu --loglevel={}", *level);
|
||||
let args = format!("nu --loglevel={}", level);
|
||||
ui.parse(&args)?;
|
||||
assert_eq!(ui.loglevel().unwrap(), Ok(level.to_string()));
|
||||
|
||||
let ui = cli_app();
|
||||
let args = format!("nu -l {}", *level);
|
||||
let args = format!("nu -l {}", level);
|
||||
ui.parse(&args)?;
|
||||
assert_eq!(ui.loglevel().unwrap(), Ok(level.to_string()));
|
||||
}
|
||||
@ -541,11 +541,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn can_use_test_binaries() -> Result<(), ShellError> {
|
||||
for binarie_name in &[
|
||||
for binarie_name in [
|
||||
"echo_env", "cococo", "iecho", "fail", "nonu", "chop", "repeater", "meow",
|
||||
] {
|
||||
let ui = cli_app();
|
||||
let args = format!("nu --testbin={}", *binarie_name);
|
||||
let args = format!("nu --testbin={}", binarie_name);
|
||||
ui.parse(&args)?;
|
||||
assert_eq!(ui.testbin().unwrap(), Ok(binarie_name.to_string()));
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ impl Options {
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &str) -> Option<Value> {
|
||||
self.inner.borrow().get(key).map(Clone::clone)
|
||||
self.inner.borrow().get(key).cloned()
|
||||
}
|
||||
|
||||
pub fn put(&self, key: &str, value: Value) {
|
||||
|
@ -67,48 +67,37 @@ impl OptionsParser for NuParser {
|
||||
}
|
||||
};
|
||||
|
||||
let value =
|
||||
value
|
||||
.map(|v| match k.as_ref() {
|
||||
"testbin" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if testbins().iter().any(|n| name == *n) {
|
||||
Some(v)
|
||||
} else {
|
||||
Some(
|
||||
UntaggedValue::Error(
|
||||
ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
),
|
||||
)
|
||||
.into_value(v.tag),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Some(v)
|
||||
}
|
||||
let value = value.map(|v| match k.as_ref() {
|
||||
"testbin" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if testbins().iter().any(|n| name == *n) {
|
||||
v
|
||||
} else {
|
||||
UntaggedValue::Error(ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
))
|
||||
.into_value(v.tag)
|
||||
}
|
||||
"loglevel" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if loglevels().iter().any(|n| name == *n) {
|
||||
Some(v)
|
||||
} else {
|
||||
Some(
|
||||
UntaggedValue::Error(
|
||||
ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
),
|
||||
)
|
||||
.into_value(v.tag),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Some(v)
|
||||
}
|
||||
} else {
|
||||
v
|
||||
}
|
||||
}
|
||||
"loglevel" => {
|
||||
if let Ok(name) = v.as_string() {
|
||||
if loglevels().iter().any(|n| name == *n) {
|
||||
v
|
||||
} else {
|
||||
UntaggedValue::Error(ShellError::untagged_runtime_error(
|
||||
format!("{} is not supported.", name),
|
||||
))
|
||||
.into_value(v.tag)
|
||||
}
|
||||
_ => Some(v),
|
||||
})
|
||||
.flatten();
|
||||
} else {
|
||||
v
|
||||
}
|
||||
}
|
||||
_ => v,
|
||||
});
|
||||
|
||||
if let Some(value) = value {
|
||||
options.put(k, value);
|
||||
|
@ -24,6 +24,7 @@ use rustyline::{self, error::ReadlineError};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ParserScope;
|
||||
use nu_path::expand_tilde;
|
||||
use nu_protocol::{hir::ExternalRedirection, ConfigPath, UntaggedValue, Value};
|
||||
|
||||
use log::trace;
|
||||
@ -33,7 +34,7 @@ use std::path::PathBuf;
|
||||
|
||||
// Name of environment variable where the prompt could be stored
|
||||
#[cfg(feature = "rustyline-support")]
|
||||
const PROMPT_STRING: &str = "PROMPT_STRING";
|
||||
const PROMPT_COMMAND: &str = "PROMPT_COMMAND";
|
||||
|
||||
pub fn search_paths() -> Vec<std::path::PathBuf> {
|
||||
use std::env;
|
||||
@ -54,7 +55,7 @@ pub fn search_paths() -> Vec<std::path::PathBuf> {
|
||||
{
|
||||
for pipeline in pipelines {
|
||||
if let Ok(plugin_dir) = pipeline.as_string() {
|
||||
search_paths.push(PathBuf::from(plugin_dir));
|
||||
search_paths.push(expand_tilde(plugin_dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,7 +166,10 @@ pub fn cli(
|
||||
// Store cmd duration in an env var
|
||||
context.scope.add_env_var(
|
||||
"CMD_DURATION_MS",
|
||||
format!("{}", startup_commands_start_time.elapsed().as_millis()),
|
||||
startup_commands_start_time
|
||||
.elapsed()
|
||||
.as_millis()
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
if options.perf {
|
||||
@ -298,9 +302,9 @@ pub fn cli(
|
||||
|
||||
let cwd = context.shell_manager().path();
|
||||
|
||||
// Check if the PROMPT_STRING env variable is set. This env variable
|
||||
// Check if the PROMPT_COMMAND env variable is set. This env variable
|
||||
// contains nu code that is used to overwrite the prompt
|
||||
let colored_prompt = match context.scope.get_env(PROMPT_STRING) {
|
||||
let colored_prompt = match context.scope.get_env(PROMPT_COMMAND) {
|
||||
Some(env_prompt) => evaluate_prompt_string(&env_prompt, &context, &cwd),
|
||||
None => {
|
||||
if let Some(prompt) = &prompt {
|
||||
@ -353,7 +357,7 @@ pub fn cli(
|
||||
// Store cmd duration in an env var
|
||||
context.scope.add_env_var(
|
||||
"CMD_DURATION_MS",
|
||||
format!("{}", cmd_start_time.elapsed().as_millis()),
|
||||
cmd_start_time.elapsed().as_millis().to_string(),
|
||||
);
|
||||
|
||||
match line {
|
||||
@ -368,7 +372,7 @@ pub fn cli(
|
||||
LineResult::ClearHistory => {
|
||||
if options.save_history {
|
||||
rl.clear_history();
|
||||
let _ = rl.append_history(&history_path);
|
||||
std::fs::remove_file(&history_path)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,8 +401,7 @@ pub fn cli(
|
||||
.lock()
|
||||
.global_config
|
||||
.as_ref()
|
||||
.map(|cfg| cfg.var("ctrlc_exit"))
|
||||
.flatten()
|
||||
.and_then(|cfg| cfg.var("ctrlc_exit"))
|
||||
.map(|ctrl_c| ctrl_c.is_true())
|
||||
.unwrap_or(false); // default behavior is to allow CTRL-C spamming similar to other shells
|
||||
|
||||
|
@ -461,7 +461,7 @@ pub(crate) fn load_keybindings(
|
||||
if let Ok(contents) = contents {
|
||||
let keybindings: Keybindings = serde_yaml::from_str(&contents)?;
|
||||
// eprintln!("{:#?}", keybindings);
|
||||
for keybinding in keybindings.into_iter() {
|
||||
for keybinding in keybindings {
|
||||
let (k, b) = convert_keybinding(keybinding);
|
||||
// eprintln!("{:?} {:?}", k, b);
|
||||
|
||||
|
@ -5,53 +5,48 @@ description = "CLI for nushell"
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
name = "nu-command"
|
||||
version = "0.36.0"
|
||||
version = "0.39.0"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
nu-data = { version = "0.36.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.36.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.36.0", path="../nu-errors" }
|
||||
nu-json = { version = "0.36.0", path="../nu-json" }
|
||||
nu-path = { version = "0.36.0", path="../nu-path" }
|
||||
nu-parser = { version = "0.36.0", path="../nu-parser" }
|
||||
nu-plugin = { version = "0.36.0", path="../nu-plugin" }
|
||||
nu-protocol = { version = "0.36.0", path="../nu-protocol" }
|
||||
nu-serde = { version = "0.36.0", path="../nu-serde" }
|
||||
nu-source = { version = "0.36.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.36.0", path="../nu-stream" }
|
||||
nu-table = { version = "0.36.0", path="../nu-table" }
|
||||
nu-test-support = { version = "0.36.0", path="../nu-test-support" }
|
||||
nu-value-ext = { version = "0.36.0", path="../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.36.0", path="../nu-ansi-term" }
|
||||
nu-pretty-hex = { version = "0.36.0", path="../nu-pretty-hex" }
|
||||
nu-data = { version = "0.39.0", path="../nu-data" }
|
||||
nu-engine = { version = "0.39.0", path="../nu-engine" }
|
||||
nu-errors = { version = "0.39.0", path="../nu-errors" }
|
||||
nu-json = { version = "0.39.0", path="../nu-json" }
|
||||
nu-path = { version = "0.39.0", path="../nu-path" }
|
||||
nu-parser = { version = "0.39.0", path="../nu-parser" }
|
||||
nu-plugin = { version = "0.39.0", path="../nu-plugin" }
|
||||
nu-protocol = { version = "0.39.0", path="../nu-protocol" }
|
||||
nu-serde = { version = "0.39.0", path="../nu-serde" }
|
||||
nu-source = { version = "0.39.0", path="../nu-source" }
|
||||
nu-stream = { version = "0.39.0", path="../nu-stream" }
|
||||
nu-table = { version = "0.39.0", path="../nu-table" }
|
||||
nu-test-support = { version = "0.39.0", path="../nu-test-support" }
|
||||
nu-value-ext = { version = "0.39.0", path="../nu-value-ext" }
|
||||
nu-ansi-term = { version = "0.39.0", path="../nu-ansi-term" }
|
||||
nu-pretty-hex = { version = "0.39.0", path="../nu-pretty-hex" }
|
||||
|
||||
url = "2.2.1"
|
||||
mime = "0.3.16"
|
||||
Inflector = "0.11"
|
||||
arboard = { version="1.1.0", optional=true }
|
||||
base64 = "0.13.0"
|
||||
bigdecimal = { package = "bigdecimal-rs", version = "0.2.1", features = ["serde"] }
|
||||
byte-unit = "4.0.9"
|
||||
bytes = "1.0.1"
|
||||
calamine = "0.18.0"
|
||||
chrono = { version="0.4.19", features=["serde"] }
|
||||
chrono-tz = "0.5.3"
|
||||
codespan-reporting = "0.11.0"
|
||||
crossterm = { version="0.19.0", optional=true }
|
||||
csv = "1.1.3"
|
||||
ctrlc = { version="3.1.7", optional=true }
|
||||
derive-new = "0.5.8"
|
||||
directories-next = "2.0.0"
|
||||
dirs-next = "2.0.0"
|
||||
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"] }
|
||||
getset = "0.1.1"
|
||||
glob = "0.3.0"
|
||||
htmlescape = "0.3.1"
|
||||
ical = "0.7.0"
|
||||
@ -61,49 +56,42 @@ lazy_static = "1.*"
|
||||
log = "0.4.14"
|
||||
md-5 = "0.9.1"
|
||||
meval = "0.2.0"
|
||||
minus = { version="3.4.0", optional=true, features=["async_std_lib", "search"] }
|
||||
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"
|
||||
query_interface = "0.3.5"
|
||||
quick-xml = "0.22"
|
||||
rand = "0.8"
|
||||
rayon = "1.5.0"
|
||||
regex = "1.4.3"
|
||||
reqwest = {version = "0.11", optional = true }
|
||||
roxmltree = "0.14.0"
|
||||
rust-embed = "5.9.0"
|
||||
rustyline = { version="9.0.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"
|
||||
strip-ansi-escapes = "0.1.0"
|
||||
sxd-document = "0.3.2"
|
||||
sxd-xpath = "0.4.2"
|
||||
sysinfo = { version = "0.20.2", optional = true }
|
||||
thiserror = "1.0.26"
|
||||
tempfile = "3.2.0"
|
||||
term = { version="0.7.0", optional=true }
|
||||
term_size = "0.3.2"
|
||||
termcolor = "1.1.2"
|
||||
titlecase = "1.1.0"
|
||||
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||
toml = "0.5.8"
|
||||
trash = { version="1.3.0", optional=true }
|
||||
unicode-segmentation = "1.8"
|
||||
url = "2.2.0"
|
||||
uuid_crate = { package="uuid", version="0.8.2", features=["v4"], optional=true }
|
||||
which = { version="4.1.0", optional=true }
|
||||
zip = { version="0.5.9", optional=true }
|
||||
digest = "0.9.0"
|
||||
|
||||
[dependencies.polars]
|
||||
version = "0.15.1"
|
||||
version = "0.16.0"
|
||||
optional = true
|
||||
features = ["parquet", "json", "random", "pivot", "strings", "is_in", "temporal"]
|
||||
features = ["parquet", "json", "random", "pivot", "strings", "is_in", "temporal", "cum_agg", "rolling_window"]
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
umask = "1.0.0"
|
||||
@ -112,13 +100,8 @@ 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.25.3"
|
||||
# [target.'cfg(not(windows))'.dependencies]
|
||||
# num-format = { version = "0.4", features = ["with-system-locale"] }
|
||||
|
||||
[build-dependencies]
|
||||
shadow-rs = "0.6"
|
||||
@ -133,5 +116,8 @@ clipboard-cli = ["arboard"]
|
||||
rustyline-support = ["rustyline"]
|
||||
stable = []
|
||||
trash-support = ["trash"]
|
||||
table-pager = ["minus", "crossterm"]
|
||||
dataframe = ["nu-protocol/dataframe", "polars"]
|
||||
fetch = ["reqwest", "tokio"]
|
||||
post = ["reqwest", "tokio"]
|
||||
sys = ["sysinfo"]
|
||||
ps = ["sysinfo"]
|
||||
|
@ -4,7 +4,10 @@ use nu_engine::{MaybeTextCodec, StringOrBinary};
|
||||
use nu_test_support::NATIVE_PATH_ENV_VAR;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
#[allow(unused)]
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc;
|
||||
use std::{borrow::Cow, io::BufReader};
|
||||
@ -17,6 +20,9 @@ use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
|
||||
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
use nu_source::Tag;
|
||||
|
||||
#[cfg(feature = "which")]
|
||||
use which::which_in;
|
||||
|
||||
pub(crate) fn run_external_command(
|
||||
command: ExternalCommand,
|
||||
context: &mut EvaluationContext,
|
||||
@ -104,7 +110,7 @@ fn run_with_stdin(
|
||||
let process_args = command_args
|
||||
.iter()
|
||||
.map(|(arg, _is_literal)| {
|
||||
let arg = nu_path::expand_tilde_string(Cow::Borrowed(arg));
|
||||
let arg = nu_path::expand_tilde(arg).to_string_lossy().to_string();
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
@ -141,6 +147,79 @@ fn run_with_stdin(
|
||||
)
|
||||
}
|
||||
|
||||
/// Spawn a direct exe
|
||||
#[allow(unused)]
|
||||
fn spawn_exe(full_path: PathBuf, args: &[String]) -> Command {
|
||||
let mut process = Command::new(full_path);
|
||||
for arg in args {
|
||||
process.arg(&arg);
|
||||
}
|
||||
process
|
||||
}
|
||||
|
||||
/// Spawn a cmd command with `cmd /c args...`
|
||||
fn spawn_cmd_command(command: &ExternalCommand, args: &[String]) -> Command {
|
||||
let mut process = Command::new("cmd");
|
||||
process.arg("/c");
|
||||
process.arg(&command.name);
|
||||
for arg in args {
|
||||
// Clean the args before we use them:
|
||||
// https://stackoverflow.com/questions/1200235/how-to-pass-a-quoted-pipe-character-to-cmd-exe
|
||||
// cmd.exe needs to have a caret to escape a pipe
|
||||
let arg = arg.replace("|", "^|");
|
||||
process.arg(&arg);
|
||||
}
|
||||
process
|
||||
}
|
||||
|
||||
/// Spawn a sh command with `sh -c args...`
|
||||
fn spawn_sh_command(command: &ExternalCommand, args: &[String]) -> Command {
|
||||
let cmd_with_args = vec![command.name.clone(), args.join(" ")].join(" ");
|
||||
let mut process = Command::new("sh");
|
||||
process.arg("-c").arg(cmd_with_args);
|
||||
process
|
||||
}
|
||||
|
||||
/// a function to spawn any external command
|
||||
#[allow(unused)] // for minimal builds cwd is unused
|
||||
fn spawn_any(command: &ExternalCommand, args: &[String], cwd: &str) -> Command {
|
||||
// resolve the executable name if it is spawnable directly
|
||||
#[cfg(feature = "which")]
|
||||
// TODO add more available paths to `env::var_os("PATH")`?
|
||||
if let Result::Ok(full_path) = which_in(&command.name, env::var_os("PATH"), cwd) {
|
||||
if let Some(extension) = full_path.extension() {
|
||||
#[cfg(windows)]
|
||||
if extension.eq_ignore_ascii_case("exe") {
|
||||
// if exe spawn it directly
|
||||
return spawn_exe(full_path, args);
|
||||
} else {
|
||||
// TODO implement special care for various executable types such as .bat, .ps1, .cmd, etc
|
||||
// https://github.com/mklement0/Native/blob/e0e0b8785cad39a73053e35084d1f60d87fbac58/Native.psm1#L749
|
||||
// otherwise shell out to cmd
|
||||
return spawn_cmd_command(command, args);
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
if !["sh", "bash"]
|
||||
.iter()
|
||||
.any(|ext| extension.eq_ignore_ascii_case(ext))
|
||||
{
|
||||
// if exe spawn it directly
|
||||
return spawn_exe(full_path, args);
|
||||
} else {
|
||||
// otherwise shell out to sh
|
||||
return spawn_sh_command(command, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
// in all the other cases shell out
|
||||
if cfg!(windows) {
|
||||
spawn_cmd_command(command, args)
|
||||
} else {
|
||||
// TODO what happens if that os doesn't support spawning sh?
|
||||
spawn_sh_command(command, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn(
|
||||
command: &ExternalCommand,
|
||||
path: &str,
|
||||
@ -151,31 +230,7 @@ fn spawn(
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let command = command.clone();
|
||||
|
||||
let mut process = {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut process = Command::new("cmd");
|
||||
process.arg("/c");
|
||||
process.arg(&command.name);
|
||||
for arg in args {
|
||||
// Clean the args before we use them:
|
||||
// https://stackoverflow.com/questions/1200235/how-to-pass-a-quoted-pipe-character-to-cmd-exe
|
||||
// cmd.exe needs to have a caret to escape a pipe
|
||||
let arg = arg.replace("|", "^|");
|
||||
process.arg(&arg);
|
||||
}
|
||||
process
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let cmd_with_args = vec![command.name.clone(), args.join(" ")].join(" ");
|
||||
let mut process = Command::new("sh");
|
||||
process.arg("-c").arg(cmd_with_args);
|
||||
process
|
||||
}
|
||||
};
|
||||
|
||||
let mut process = spawn_any(&command, args, path);
|
||||
process.current_dir(path);
|
||||
trace!(target: "nu::run::external", "cwd = {:?}", &path);
|
||||
|
||||
@ -454,7 +509,7 @@ fn spawn(
|
||||
Ok(stream.into_input_stream())
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("{}", e),
|
||||
e.to_string(),
|
||||
"failed to spawn",
|
||||
&command.name_tag,
|
||||
)),
|
||||
|
@ -22,6 +22,7 @@ impl WholeStreamCommand for Histogram {
|
||||
None,
|
||||
)
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column name to give the histogram's frequency column",
|
||||
)
|
||||
|
@ -13,6 +13,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into binary").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to binary (for table input)",
|
||||
)
|
||||
|
118
crates/nu-command/src/commands/conversions/into/column_path.rs
Normal file
118
crates/nu-command/src/commands/conversions/into/column_path.rs
Normal file
@ -0,0 +1,118 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"into column_path"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into column_path").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"values to convert to column_path",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert value to column path"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
into_filepath(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert string to column_path in table",
|
||||
example: "echo [[name]; ['/dev/null'] ['C:\\Program Files'] ['../../Cargo.toml']] | into column_path name",
|
||||
result: Some(vec![
|
||||
UntaggedValue::row(indexmap! {
|
||||
"name".to_string() => UntaggedValue::column_path("/dev/null", Span::unknown()).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"name".to_string() => UntaggedValue::column_path("C:\\Program Files", Span::unknown()).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"name".to_string() => UntaggedValue::column_path("../../Cargo.toml", Span::unknown()).into(),
|
||||
})
|
||||
.into(),
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert string to column_path",
|
||||
example: "echo 'Cargo.toml' | into column_path",
|
||||
result: Some(vec![UntaggedValue::column_path("Cargo.toml", Span::unknown()).into()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn into_filepath(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let column_paths: Vec<ColumnPath> = args.rest(0)?;
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
action(&v, v.tag())
|
||||
} else {
|
||||
let mut ret = v;
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action(old, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
})
|
||||
.into_input_stream())
|
||||
}
|
||||
|
||||
pub fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
match &input.value {
|
||||
UntaggedValue::Primitive(prim) => Ok(UntaggedValue::column_path(
|
||||
match prim {
|
||||
Primitive::String(a_string) => a_string,
|
||||
_ => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"'into column_path' for non-string primitives",
|
||||
))
|
||||
}
|
||||
},
|
||||
Span::unknown(),
|
||||
)
|
||||
.into_value(&tag)),
|
||||
UntaggedValue::Row(_) => Err(ShellError::labeled_error(
|
||||
"specify column name to use, with 'into column_path COLUMN'",
|
||||
"found table",
|
||||
tag,
|
||||
)),
|
||||
_ => Err(ShellError::unimplemented(
|
||||
"'into column_path' for unsupported type",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into path").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to filepath (for table input)",
|
||||
)
|
||||
|
182
crates/nu-command/src/commands/conversions/into/filesize.rs
Normal file
182
crates/nu-command/src/commands/conversions/into/filesize.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ColumnPath, Primitive, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use num_bigint::ToBigInt;
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"into filesize"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into filesize").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to filesize (for table input)",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Convert value to filesize"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
into_filesize(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert string to filesize in table",
|
||||
example: "echo [[bytes]; ['5'] [3.2] [4] [2kb]] | into filesize bytes",
|
||||
result: Some(vec![
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(5).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(3).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(4).into(),
|
||||
})
|
||||
.into(),
|
||||
UntaggedValue::row(indexmap! {
|
||||
"bytes".to_string() => UntaggedValue::filesize(2000).into(),
|
||||
})
|
||||
.into(),
|
||||
]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert string to filesize",
|
||||
example: "echo '2' | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(2).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert decimal to filesize",
|
||||
example: "echo 8.3 | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(8).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert int to filesize",
|
||||
example: "echo 5 | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(5).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Convert file size to filesize",
|
||||
example: "echo 4KB | into filesize",
|
||||
result: Some(vec![UntaggedValue::filesize(4000).into()]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn into_filesize(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let column_paths: Vec<ColumnPath> = args.rest(0)?;
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |v| {
|
||||
if column_paths.is_empty() {
|
||||
action(&v, v.tag())
|
||||
} else {
|
||||
let mut ret = v;
|
||||
for path in &column_paths {
|
||||
ret = ret.swap_data_by_column_path(
|
||||
path,
|
||||
Box::new(move |old| action(old, old.tag())),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
})
|
||||
.into_input_stream())
|
||||
}
|
||||
|
||||
pub fn action(input: &Value, tag: impl Into<Tag>) -> Result<Value, ShellError> {
|
||||
let tag = tag.into();
|
||||
match &input.value {
|
||||
UntaggedValue::Primitive(prim) => Ok(UntaggedValue::filesize(match prim {
|
||||
Primitive::String(a_string) => match int_from_string(a_string.trim(), &tag) {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
},
|
||||
Primitive::Decimal(dec) => match dec.to_bigint() {
|
||||
Some(n) => match n.to_u64() {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"failed to convert decimal to filesize",
|
||||
));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"failed to convert decimal to filesize",
|
||||
));
|
||||
}
|
||||
},
|
||||
Primitive::Int(n_ref) => (*n_ref).try_into().map_err(|_| {
|
||||
ShellError::unimplemented("cannot convert negative integer to filesize")
|
||||
})?,
|
||||
Primitive::Filesize(a_filesize) => *a_filesize,
|
||||
_ => {
|
||||
return Err(ShellError::unimplemented(
|
||||
"'into filesize' for non-numeric primitives",
|
||||
))
|
||||
}
|
||||
})
|
||||
.into_value(&tag)),
|
||||
UntaggedValue::Row(_) => Err(ShellError::labeled_error(
|
||||
"specify column name to use, with 'into filesize COLUMN'",
|
||||
"found table",
|
||||
tag,
|
||||
)),
|
||||
_ => Err(ShellError::unimplemented(
|
||||
"'into filesize' for unsupported type",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn int_from_string(a_string: &str, tag: &Tag) -> Result<u64, ShellError> {
|
||||
match a_string.parse::<u64>() {
|
||||
Ok(n) => Ok(n),
|
||||
Err(_) => match a_string.parse::<f64>() {
|
||||
Ok(f) => match f.to_u64() {
|
||||
Some(i) => Ok(i),
|
||||
None => Err(ShellError::labeled_error(
|
||||
"Could not convert string value to filesize",
|
||||
"original value",
|
||||
tag.clone(),
|
||||
)),
|
||||
},
|
||||
Err(_) => Err(ShellError::labeled_error(
|
||||
"Could not convert string value to filesize",
|
||||
"original value",
|
||||
tag.clone(),
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
|
||||
test_examples(SubCommand {})
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into int").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to int (for table input)",
|
||||
)
|
||||
|
@ -1,10 +1,14 @@
|
||||
mod binary;
|
||||
mod column_path;
|
||||
mod command;
|
||||
mod filepath;
|
||||
mod filesize;
|
||||
mod int;
|
||||
pub mod string;
|
||||
|
||||
pub use self::filesize::SubCommand as IntoFilesize;
|
||||
pub use binary::SubCommand as IntoBinary;
|
||||
pub use column_path::SubCommand as IntoColumnPath;
|
||||
pub use command::Command as Into;
|
||||
pub use filepath::SubCommand as IntoFilepath;
|
||||
pub use int::SubCommand as IntoInt;
|
||||
|
@ -20,6 +20,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into string")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"column paths to convert to string (for table input)",
|
||||
)
|
||||
@ -158,7 +159,7 @@ pub fn action(
|
||||
}
|
||||
|
||||
fn format_int(int: i64) -> String {
|
||||
format!("{}", int)
|
||||
int.to_string()
|
||||
|
||||
// TODO once platform-specific dependencies are stable (see Cargo.toml)
|
||||
// #[cfg(windows)]
|
||||
@ -175,7 +176,7 @@ fn format_int(int: i64) -> String {
|
||||
}
|
||||
|
||||
fn format_bigint(int: &BigInt) -> String {
|
||||
format!("{}", int)
|
||||
int.to_string()
|
||||
|
||||
// TODO once platform-specific dependencies are stable (see Cargo.toml)
|
||||
// #[cfg(windows)]
|
||||
@ -229,7 +230,7 @@ fn format_decimal(mut decimal: BigDecimal, digits: Option<u64>, group_digits: bo
|
||||
let format_default_loc = |int_part: BigInt| {
|
||||
let loc = Locale::en;
|
||||
//TODO: when num_format is available for recent bigint, replace this with the locale-based format
|
||||
let (int_str, sep) = (format!("{}", int_part), String::from(loc.decimal()));
|
||||
let (int_str, sep) = (int_part.to_string(), String::from(loc.decimal()));
|
||||
|
||||
format!("{}{}{}", int_str, sep, dec_str)
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ impl WholeStreamCommand for Alias {
|
||||
Signature::build("alias")
|
||||
.required("name", SyntaxShape::String, "the name of the alias")
|
||||
.required("equals", SyntaxShape::String, "the equals sign")
|
||||
.rest(SyntaxShape::Any, "the expansion for the alias")
|
||||
.rest("rest", SyntaxShape::Any, "the expansion for the alias")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -27,7 +27,7 @@ impl WholeStreamCommand for Do {
|
||||
"ignore errors as the block runs",
|
||||
Some('i'),
|
||||
)
|
||||
.rest(SyntaxShape::Any, "the parameter(s) for the block")
|
||||
.rest("rest", SyntaxShape::Any, "the parameter(s) for the block")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -12,7 +12,7 @@ impl WholeStreamCommand for Echo {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("echo").rest(SyntaxShape::Any, "the values to echo")
|
||||
Signature::build("echo").rest("rest", SyntaxShape::Any, "the values to echo")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
109
crates/nu-command/src/commands/core_commands/error/make.rs
Normal file
109
crates/nu-command/src/commands/core_commands/error/make.rs
Normal file
@ -0,0 +1,109 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Primitive, Signature, UntaggedValue, Value};
|
||||
|
||||
pub struct SubCommand;
|
||||
|
||||
impl WholeStreamCommand for SubCommand {
|
||||
fn name(&self) -> &str {
|
||||
"error make"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("error make")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Create an error."
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
.map(|value| {
|
||||
make_error(&value)
|
||||
.map(|err| UntaggedValue::Error(err).into_value(value.tag()))
|
||||
.unwrap_or_else(|| {
|
||||
UntaggedValue::Error(ShellError::untagged_runtime_error(
|
||||
"Creating error value not supported.",
|
||||
))
|
||||
.into_value(value.tag())
|
||||
})
|
||||
})
|
||||
.into_output_stream())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Creates a labeled error",
|
||||
example: r#"[
|
||||
[ msg, labels, span];
|
||||
["The message", "Helpful message here", ([[start, end]; [0, 141]])]
|
||||
] | error make"#,
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn make_error(value: &Value) -> Option<ShellError> {
|
||||
if let Value {
|
||||
value: UntaggedValue::Row(dict),
|
||||
..
|
||||
} = value
|
||||
{
|
||||
let msg = dict.get_data_by_key("msg".spanned_unknown());
|
||||
|
||||
let labels =
|
||||
dict.get_data_by_key("labels".spanned_unknown())
|
||||
.and_then(|table| match &table.value {
|
||||
UntaggedValue::Table(_) => table
|
||||
.table_entries()
|
||||
.map(|value| value.as_string().ok())
|
||||
.collect(),
|
||||
UntaggedValue::Primitive(Primitive::String(label)) => {
|
||||
Some(vec![label.to_string()])
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
let _anchor = dict.get_data_by_key("tag".spanned_unknown());
|
||||
let span = dict.get_data_by_key("span".spanned_unknown());
|
||||
|
||||
if msg.is_none() || labels.is_none() || span.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let msg = msg.and_then(|msg| msg.as_string().ok());
|
||||
|
||||
if let Some(labels) = labels {
|
||||
if labels.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(ShellError::labeled_error(
|
||||
msg.expect("Message will always be present."),
|
||||
&labels[0],
|
||||
span.map(|data| match data {
|
||||
Value {
|
||||
value: UntaggedValue::Row(vals),
|
||||
..
|
||||
} => match (vals.entries.get("start"), vals.entries.get("end")) {
|
||||
(Some(start), Some(end)) => {
|
||||
let start = start.as_usize().ok().unwrap_or(0);
|
||||
let end = end.as_usize().ok().unwrap_or(0);
|
||||
|
||||
Span::new(start, end)
|
||||
}
|
||||
(_, _) => Span::unknown(),
|
||||
},
|
||||
_ => Span::unknown(),
|
||||
})
|
||||
.unwrap_or_else(Span::unknown),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
mod make;
|
||||
|
||||
pub use make::SubCommand as ErrorMake;
|
110
crates/nu-command/src/commands/core_commands/find.rs
Normal file
110
crates/nu-command/src/commands/core_commands/find.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
|
||||
pub struct Find;
|
||||
|
||||
impl WholeStreamCommand for Find {
|
||||
fn name(&self) -> &str {
|
||||
"find"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("find").rest("rest", SyntaxShape::String, "search term")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Find text in the output of a previous command"
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
find(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Search pipeline output for multiple terms",
|
||||
example: r#"ls | find toml md sh"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Search strings for term(s)",
|
||||
example: r#"echo Cargo.toml | find toml"#,
|
||||
result: Some(vec![Value::from("Cargo.toml")]),
|
||||
},
|
||||
Example {
|
||||
description: "Search a number list for term(s)",
|
||||
example: r#"[1 2 3 4 5] | find 5"#,
|
||||
result: Some(vec![UntaggedValue::int(5).into()]),
|
||||
},
|
||||
Example {
|
||||
description: "Search string list for term(s)",
|
||||
example: r#"[moe larry curly] | find l"#,
|
||||
result: Some(vec![Value::from("larry"), Value::from("curly")]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
fn row_contains(row: &Dictionary, search_terms: Vec<String>) -> bool {
|
||||
for term in search_terms {
|
||||
for (k, v) in &row.entries {
|
||||
let key = k.to_string().trim().to_lowercase();
|
||||
let value = v.convert_to_string().trim().to_lowercase();
|
||||
if key.contains(&term) || value.contains(&term) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn find(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let rest: Vec<Value> = args.rest(0)?;
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.filter(move |row| match &row.value {
|
||||
UntaggedValue::Row(row) => {
|
||||
let sterms: Vec<String> = rest
|
||||
.iter()
|
||||
.map(|t| t.convert_to_string().trim().to_lowercase())
|
||||
.collect();
|
||||
row_contains(row, sterms)
|
||||
}
|
||||
UntaggedValue::Primitive(_p) => {
|
||||
// eprint!("prim {}", p.type_name());
|
||||
let sterms: Vec<String> = rest
|
||||
.iter()
|
||||
.map(|t| t.convert_to_string().trim().to_lowercase())
|
||||
.collect();
|
||||
|
||||
let prim_string = &row.convert_to_string().trim().to_lowercase();
|
||||
for term in sterms {
|
||||
if prim_string.contains(&term) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.into_output_stream())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Find;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test as test_examples;
|
||||
|
||||
test_examples(Find {})
|
||||
}
|
||||
}
|
@ -18,7 +18,11 @@ impl WholeStreamCommand for Help {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("help")
|
||||
.rest(SyntaxShape::String, "the name of command to get help on")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::String,
|
||||
"the name of command to get help on",
|
||||
)
|
||||
.named(
|
||||
"find",
|
||||
SyntaxShape::String,
|
||||
@ -298,7 +302,7 @@ pub fn signature_dict(signature: Signature, tag: impl Into<Tag>) -> Value {
|
||||
let tag = tag.into();
|
||||
let mut sig = TaggedListBuilder::new(&tag);
|
||||
|
||||
for arg in signature.positional.iter() {
|
||||
for arg in &signature.positional {
|
||||
let is_required = matches!(arg.0, PositionalType::Mandatory(_, _));
|
||||
|
||||
sig.push_value(for_spec(arg.0.name(), "argument", is_required, &tag));
|
||||
@ -309,7 +313,7 @@ pub fn signature_dict(signature: Signature, tag: impl Into<Tag>) -> Value {
|
||||
sig.push_value(for_spec("rest", "argument", is_required, &tag));
|
||||
}
|
||||
|
||||
for (name, ty) in signature.named.iter() {
|
||||
for (name, ty) in &signature.named {
|
||||
match ty.0 {
|
||||
NamedType::Mandatory(_, _) => sig.push_value(for_spec(name, "flag", true, &tag)),
|
||||
NamedType::Optional(_, _) => sig.push_value(for_spec(name, "flag", false, &tag)),
|
||||
|
@ -100,18 +100,15 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
context.scope.add_vars(&condition.captured.entries);
|
||||
|
||||
//FIXME: should we use the scope that's brought in as well?
|
||||
let condition = evaluate_baseline_expr(cond, &*context);
|
||||
match condition {
|
||||
let condition = evaluate_baseline_expr(cond, &context);
|
||||
let result = match condition {
|
||||
Ok(condition) => match condition.as_bool() {
|
||||
Ok(b) => {
|
||||
let result = if b {
|
||||
run_block(&then_case.block, &*context, input, external_redirection)
|
||||
if b {
|
||||
run_block(&then_case.block, &context, input, external_redirection)
|
||||
} else {
|
||||
run_block(&else_case.block, &*context, input, external_redirection)
|
||||
};
|
||||
context.scope.exit_scope();
|
||||
|
||||
result
|
||||
run_block(&else_case.block, &context, input, external_redirection)
|
||||
}
|
||||
}
|
||||
Err(e) => Ok(OutputStream::from_stream(
|
||||
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
|
||||
@ -120,13 +117,16 @@ fn if_command(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Err(e) => Ok(OutputStream::from_stream(
|
||||
vec![UntaggedValue::Error(e).into_untagged_value()].into_iter(),
|
||||
)),
|
||||
}
|
||||
};
|
||||
context.scope.exit_scope();
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::If;
|
||||
use super::ShellError;
|
||||
use nu_test_support::nu;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
@ -134,4 +134,21 @@ mod tests {
|
||||
|
||||
test_examples(If {})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_doesnt_leak_on_error() {
|
||||
let actual = nu!(
|
||||
".",
|
||||
r#"
|
||||
def test-leak [] {
|
||||
let var = "hello"
|
||||
if 0 == "" {echo ok} {echo not}
|
||||
}
|
||||
test-leak
|
||||
echo $var
|
||||
"#
|
||||
);
|
||||
|
||||
assert!(actual.err.contains("unknown variable"));
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ mod def;
|
||||
mod describe;
|
||||
mod do_;
|
||||
pub(crate) mod echo;
|
||||
mod error;
|
||||
mod find;
|
||||
mod help;
|
||||
mod history;
|
||||
mod if_;
|
||||
@ -27,6 +29,8 @@ pub use def::Def;
|
||||
pub use describe::Describe;
|
||||
pub use do_::Do;
|
||||
pub use echo::Echo;
|
||||
pub use error::*;
|
||||
pub use find::Find;
|
||||
pub use help::Help;
|
||||
pub use history::History;
|
||||
pub use if_::If;
|
||||
|
@ -4,7 +4,7 @@ use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_path::canonicalize;
|
||||
use nu_path::canonicalize_with;
|
||||
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
|
||||
use nu_source::Tagged;
|
||||
|
||||
@ -56,7 +56,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
tag,
|
||||
}) = load_path
|
||||
{
|
||||
let path = canonicalize(shell_manager.path(), load_path).map_err(|_| {
|
||||
let path = canonicalize_with(load_path, shell_manager.path()).map_err(|_| {
|
||||
ShellError::labeled_error(
|
||||
"Cannot load plugins from directory",
|
||||
"directory not found",
|
||||
|
@ -41,7 +41,7 @@ impl WholeStreamCommand for Command {
|
||||
"custom configuration source file",
|
||||
None,
|
||||
)
|
||||
.rest(SyntaxShape::String, "source file(s) to run")
|
||||
.rest("rest", SyntaxShape::String, "source file(s) to run")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -2,11 +2,11 @@ use crate::prelude::*;
|
||||
use nu_engine::{script, WholeStreamCommand};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_path::expand_path;
|
||||
use nu_path::{canonicalize, canonicalize_with};
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use std::{borrow::Cow, path::Path};
|
||||
use std::path::Path;
|
||||
|
||||
pub struct Source;
|
||||
|
||||
@ -32,7 +32,7 @@ impl WholeStreamCommand for Source {
|
||||
"Runs a script file in the current context."
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
source(args)
|
||||
}
|
||||
|
||||
@ -41,14 +41,66 @@ impl WholeStreamCommand for Source {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
pub fn source(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let ctx = &args.context;
|
||||
let filename: Tagged<String> = args.req(0)?;
|
||||
|
||||
let source_file = Path::new(&filename.item);
|
||||
|
||||
// Note: this is a special case for setting the context from a command
|
||||
// In this case, if we don't set it now, we'll lose the scope that this
|
||||
// variable should be set into.
|
||||
let contents = std::fs::read_to_string(&expand_path(Cow::Borrowed(Path::new(&filename.item))));
|
||||
|
||||
let lib_dirs = &ctx
|
||||
.configs()
|
||||
.lock()
|
||||
.global_config
|
||||
.as_ref()
|
||||
.map(|configuration| match configuration.var("lib_dirs") {
|
||||
Some(paths) => paths
|
||||
.table_entries()
|
||||
.cloned()
|
||||
.map(|path| path.as_string())
|
||||
.collect(),
|
||||
None => vec![],
|
||||
});
|
||||
|
||||
if let Some(dir) = lib_dirs {
|
||||
for lib_path in dir {
|
||||
match lib_path {
|
||||
Ok(name) => {
|
||||
let path = if let Ok(p) = canonicalize_with(&source_file, name) {
|
||||
p
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Ok(contents) = std::fs::read_to_string(path) {
|
||||
let result = script::run_script_standalone(contents, true, ctx, false);
|
||||
|
||||
if let Err(err) = result {
|
||||
ctx.error(err);
|
||||
}
|
||||
return Ok(OutputStream::empty());
|
||||
}
|
||||
}
|
||||
Err(reason) => {
|
||||
ctx.error(reason.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let path = canonicalize(source_file).map_err(|e| {
|
||||
ShellError::labeled_error(
|
||||
format!("Can't load source file. Reason: {}", e.to_string()),
|
||||
"Can't load this file",
|
||||
filename.span(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let contents = std::fs::read_to_string(path);
|
||||
|
||||
match contents {
|
||||
Ok(contents) => {
|
||||
let result = script::run_script_standalone(contents, true, ctx, false);
|
||||
@ -56,16 +108,16 @@ pub fn source(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
if let Err(err) = result {
|
||||
ctx.error(err);
|
||||
}
|
||||
Ok(ActionStream::empty())
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
ctx.error(ShellError::labeled_error(
|
||||
"Can't load file to source",
|
||||
"can't load file",
|
||||
format!("Can't load source file. Reason: {}", e.to_string()),
|
||||
"Can't load this file",
|
||||
filename.span(),
|
||||
));
|
||||
|
||||
Ok(ActionStream::empty())
|
||||
Ok(OutputStream::empty())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, TaggedDictBuilder, UntaggedValue};
|
||||
use nu_protocol::{Primitive, Signature, TaggedDictBuilder, UntaggedValue, Value};
|
||||
|
||||
pub struct Tags;
|
||||
|
||||
@ -18,37 +18,64 @@ impl WholeStreamCommand for Tags {
|
||||
"Read the tags (metadata) for values."
|
||||
}
|
||||
|
||||
fn run_with_actions(&self, args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(tags(args))
|
||||
}
|
||||
}
|
||||
|
||||
fn tags(args: CommandArgs) -> ActionStream {
|
||||
args.input
|
||||
.map(move |v| {
|
||||
let mut tags = TaggedDictBuilder::new(v.tag());
|
||||
{
|
||||
let anchor = v.anchor();
|
||||
let span = v.tag.span;
|
||||
let mut dict = TaggedDictBuilder::new(v.tag());
|
||||
dict.insert_untagged("start", UntaggedValue::int(span.start() as i64));
|
||||
dict.insert_untagged("end", UntaggedValue::int(span.end() as i64));
|
||||
tags.insert_value("span", dict.into_value());
|
||||
fn build_tag_table(tag: impl Into<Tag>) -> Value {
|
||||
let tag = tag.into();
|
||||
let span = tag.span;
|
||||
|
||||
match anchor {
|
||||
Some(AnchorLocation::File(source)) => {
|
||||
tags.insert_untagged("anchor", UntaggedValue::string(source));
|
||||
}
|
||||
Some(AnchorLocation::Url(source)) => {
|
||||
tags.insert_untagged("anchor", UntaggedValue::string(source));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
TaggedDictBuilder::build(tag.clone(), |tags| {
|
||||
if let Some(anchor) = anchor_as_value(&tag) {
|
||||
tags.insert_value("anchor", anchor);
|
||||
}
|
||||
|
||||
tags.insert_value(
|
||||
"span",
|
||||
TaggedDictBuilder::build(tag.clone(), |span_dict| {
|
||||
span_dict.insert_untagged("start", UntaggedValue::int(span.start() as i64));
|
||||
span_dict.insert_untagged("end", UntaggedValue::int(span.end() as i64));
|
||||
}),
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
fn tags(args: CommandArgs) -> OutputStream {
|
||||
if args.input.is_empty() {
|
||||
OutputStream::one(build_tag_table(&args.name_tag()))
|
||||
} else {
|
||||
args.input
|
||||
.map(move |v| build_tag_table(v.tag()))
|
||||
.into_output_stream()
|
||||
}
|
||||
}
|
||||
|
||||
fn anchor_as_value(tag: &Tag) -> Option<Value> {
|
||||
let anchor = tag.anchor.as_ref();
|
||||
|
||||
anchor.as_ref()?;
|
||||
|
||||
Some(TaggedDictBuilder::build(tag, |table| {
|
||||
let value = match anchor {
|
||||
Some(AnchorLocation::File(path)) => {
|
||||
Some(("file", UntaggedValue::from(path.to_string())))
|
||||
}
|
||||
Some(AnchorLocation::Url(destination)) => {
|
||||
Some(("url", UntaggedValue::from(destination.to_string())))
|
||||
}
|
||||
Some(AnchorLocation::Source(text)) => Some((
|
||||
"source",
|
||||
UntaggedValue::Primitive(Primitive::String(text.to_string())),
|
||||
)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
tags.into_value()
|
||||
})
|
||||
.into_action_stream()
|
||||
if let Some((key, value)) = value {
|
||||
table.insert_untagged(key, value);
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -56,7 +56,7 @@ fn tutor(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let search: Option<String> = args.opt(0).unwrap_or(None);
|
||||
let find: Option<String> = args.get_flag("find")?;
|
||||
|
||||
let search_space = vec![
|
||||
let search_space = [
|
||||
(vec!["begin"], begin_tutor()),
|
||||
(
|
||||
vec!["table", "tables", "row", "rows", "column", "columns"],
|
||||
@ -88,7 +88,7 @@ fn tutor(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if let Some(find) = find {
|
||||
let mut results = vec![];
|
||||
for search_group in search_space {
|
||||
if search_group.1.contains(&find.as_str()) {
|
||||
if search_group.1.contains(&find) {
|
||||
results.push(search_group.0[0].to_string())
|
||||
}
|
||||
}
|
||||
@ -166,7 +166,7 @@ This will get the 3rd (note that `nth` is zero-based) row in the table created
|
||||
by the `ls` command. You can use `nth` on any table created by other commands
|
||||
as well.
|
||||
|
||||
You can also access the column of data in one of two ways. If you want to want
|
||||
You can also access the column of data in one of two ways. If you want
|
||||
to keep the column as part of a new table, you can use `select`.
|
||||
```
|
||||
ls | select name
|
||||
@ -274,7 +274,7 @@ This can be helpful if you want to later processes these values.
|
||||
The `echo` command can pair well with the `each` command which can run
|
||||
code on each row, or item, of input.
|
||||
|
||||
You can continue to learn more about the `echo` command by running:
|
||||
You can continue to learn more about the `each` command by running:
|
||||
```
|
||||
tutor each
|
||||
```
|
||||
@ -383,7 +383,7 @@ fn display(tag: Tag, scope: &Scope, help: &str) -> OutputStream {
|
||||
|
||||
//TODO: support no-color mode
|
||||
let colored_example = nu_engine::Painter::paint_string(item, scope, &palette);
|
||||
build.push_str(&format!("{}", colored_example));
|
||||
build.push_str(&colored_example);
|
||||
} else {
|
||||
code_mode = true;
|
||||
build.push_str(item);
|
||||
|
@ -245,7 +245,7 @@ fn perform_groupby_aggregation(
|
||||
None => &col[..],
|
||||
};
|
||||
|
||||
res.rename(col.as_str(), new_col)
|
||||
res.rename(&col, new_col)
|
||||
.expect("Column is always there. Looping with known names");
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let other: Value = args.req_named("other")?;
|
||||
let axis: Tagged<String> = args.req_named("axis")?;
|
||||
|
||||
let axis = Axis::try_from_str(axis.item.as_str(), &axis.tag.span)?;
|
||||
let axis = Axis::try_from_str(&axis.item, &axis.tag.span)?;
|
||||
|
||||
let df_other = match other.value {
|
||||
UntaggedValue::DataFrame(df) => Ok(df),
|
||||
|
@ -53,7 +53,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let res = df
|
||||
.as_ref()
|
||||
.column(column.item.as_ref())
|
||||
.column(&column.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &column.tag.span, None))?;
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![res.clone()], &tag.span)?;
|
||||
|
@ -195,7 +195,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let name = format!("{} ({})", col.name(), col.dtype());
|
||||
ChunkedArray::<Float64Type>::new_from_opt_slice(
|
||||
name.as_str(),
|
||||
&name,
|
||||
&[
|
||||
Some(count),
|
||||
sum,
|
||||
|
@ -20,7 +20,11 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe drop").rest(SyntaxShape::Any, "column names to be dropped")
|
||||
Signature::build("dataframe drop").rest(
|
||||
"rest",
|
||||
SyntaxShape::Any,
|
||||
"column names to be dropped",
|
||||
)
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -72,7 +72,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.expect("using name from list of names from dataframe")
|
||||
.dtype();
|
||||
|
||||
let dtype_str = format!("{}", dtype);
|
||||
let dtype_str = dtype.to_string();
|
||||
dtypes.push(Value {
|
||||
value: dtype_str.into(),
|
||||
tag: Tag::default(),
|
||||
|
@ -19,7 +19,11 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe get").rest(SyntaxShape::Any, "column names to sort dataframe")
|
||||
Signature::build("dataframe get").rest(
|
||||
"rest",
|
||||
SyntaxShape::Any,
|
||||
"column names to sort dataframe",
|
||||
)
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -20,7 +20,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe group-by").rest(SyntaxShape::Any, "groupby columns")
|
||||
Signature::build("dataframe group-by").rest("rest", SyntaxShape::Any, "groupby columns")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -177,7 +177,7 @@ fn check_column_datatypes<T: AsRef<str>>(
|
||||
));
|
||||
}
|
||||
|
||||
for (l, r) in l_cols.iter().zip(r_cols.iter()) {
|
||||
for (l, r) in l_cols.iter().zip(r_cols) {
|
||||
let l_series = df_l
|
||||
.column(l.as_ref())
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, l_col_span, None))?;
|
||||
|
@ -5,6 +5,7 @@ use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Tagged;
|
||||
|
||||
use super::utils::convert_columns;
|
||||
|
||||
@ -33,6 +34,18 @@ impl WholeStreamCommand for DataFrame {
|
||||
"column names used as value columns",
|
||||
Some('v'),
|
||||
)
|
||||
.named(
|
||||
"variable_name",
|
||||
SyntaxShape::String,
|
||||
"optional name for variable column",
|
||||
Some('r'),
|
||||
)
|
||||
.named(
|
||||
"value_name",
|
||||
SyntaxShape::String,
|
||||
"optional name for value column",
|
||||
Some('l'),
|
||||
)
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
@ -105,6 +118,9 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let id_col: Vec<Value> = args.req_named("columns")?;
|
||||
let val_col: Vec<Value> = args.req_named("values")?;
|
||||
|
||||
let value_name: Option<Tagged<String>> = args.get_flag("value_name")?;
|
||||
let variable_name: Option<Tagged<String>> = args.get_flag("variable_name")?;
|
||||
|
||||
let (id_col_string, id_col_span) = convert_columns(&id_col, &tag)?;
|
||||
let (val_col_string, val_col_span) = convert_columns(&val_col, &tag)?;
|
||||
|
||||
@ -113,11 +129,21 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
check_column_datatypes(df.as_ref(), &id_col_string, &id_col_span)?;
|
||||
check_column_datatypes(df.as_ref(), &val_col_string, &val_col_span)?;
|
||||
|
||||
let res = df
|
||||
let mut res = df
|
||||
.as_ref()
|
||||
.melt(&id_col_string, &val_col_string)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
if let Some(name) = &variable_name {
|
||||
res.rename("variable", &name.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &name.tag.span, None))?;
|
||||
}
|
||||
|
||||
if let Some(name) = &value_name {
|
||||
res.rename("value", &name.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &name.tag.span, None))?;
|
||||
}
|
||||
|
||||
Ok(OutputStream::one(NuDataFrame::dataframe_to_value(res, tag)))
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ pub mod list;
|
||||
pub mod melt;
|
||||
pub mod open;
|
||||
pub mod pivot;
|
||||
pub mod rename;
|
||||
pub mod sample;
|
||||
pub mod select;
|
||||
pub mod shape;
|
||||
@ -52,6 +53,7 @@ pub use list::DataFrame as DataFrameList;
|
||||
pub use melt::DataFrame as DataFrameMelt;
|
||||
pub use open::DataFrame as DataFrameOpen;
|
||||
pub use pivot::DataFrame as DataFramePivot;
|
||||
pub use rename::DataFrame as DataFrameRename;
|
||||
pub use sample::DataFrame as DataFrameSample;
|
||||
pub use select::DataFrame as DataFrameSelect;
|
||||
pub use shape::DataFrame as DataFrameShape;
|
||||
|
@ -8,7 +8,7 @@ use nu_protocol::{
|
||||
};
|
||||
|
||||
use nu_source::Tagged;
|
||||
use polars::prelude::{CsvEncoding, CsvReader, JsonReader, ParquetReader, PolarsError, SerReader};
|
||||
use polars::prelude::{CsvEncoding, CsvReader, JsonReader, ParquetReader, SerReader};
|
||||
use std::fs::File;
|
||||
|
||||
pub struct DataFrame;
|
||||
@ -206,15 +206,6 @@ fn from_csv(args: CommandArgs) -> Result<polars::prelude::DataFrame, ShellError>
|
||||
|
||||
match csv_reader.finish() {
|
||||
Ok(df) => Ok(df),
|
||||
Err(e) => match e {
|
||||
PolarsError::Other(_) => Err(ShellError::labeled_error_with_secondary(
|
||||
"Schema error",
|
||||
"Error with the inferred schema",
|
||||
&file.tag.span,
|
||||
"You can use the argument 'infer_schema' with a number of rows large enough to better infer the schema",
|
||||
&file.tag.span,
|
||||
)),
|
||||
_ => Err(parse_polars_error::<&str>(&e, &file.tag.span, None)),
|
||||
},
|
||||
Err(e) => Err(parse_polars_error::<&str>(&e, &file.tag.span, None)),
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let mut groupby = nu_groupby.to_groupby()?;
|
||||
|
||||
let pivot = groupby.pivot(pivot_col.item.as_ref(), value_col.item.as_ref());
|
||||
let pivot = groupby.pivot(&pivot_col.item, &value_col.item);
|
||||
|
||||
let res = match op {
|
||||
Operation::Mean => pivot.mean(),
|
||||
@ -120,7 +120,7 @@ fn check_pivot_column(
|
||||
col: &Tagged<String>,
|
||||
) -> Result<(), ShellError> {
|
||||
let series = df
|
||||
.column(col.item.as_ref())
|
||||
.column(&col.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &col.tag.span, None))?;
|
||||
|
||||
match series.dtype() {
|
||||
@ -146,7 +146,7 @@ fn check_value_column(
|
||||
col: &Tagged<String>,
|
||||
) -> Result<(), ShellError> {
|
||||
let series = df
|
||||
.column(col.item.as_ref())
|
||||
.column(&col.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &col.tag.span, None))?;
|
||||
|
||||
match series.dtype() {
|
||||
|
81
crates/nu-command/src/commands/dataframe/rename.rs
Normal file
81
crates/nu-command/src/commands/dataframe/rename.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
dataframe::{Column, NuDataFrame},
|
||||
Signature, SyntaxShape, UntaggedValue,
|
||||
};
|
||||
|
||||
use nu_source::Tagged;
|
||||
|
||||
use super::utils::parse_polars_error;
|
||||
pub struct DataFrame;
|
||||
|
||||
impl WholeStreamCommand for DataFrame {
|
||||
fn name(&self) -> &str {
|
||||
"dataframe rename-col"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"[DataFrame] rename a dataframe column"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe rename-col")
|
||||
.required("from", SyntaxShape::String, "column name to be renamed")
|
||||
.required("to", SyntaxShape::String, "new column name")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
command(args)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Renames a dataframe column",
|
||||
example: "[[a b]; [1 2] [3 4]] | dataframe to-df | dataframe rename-col a ab",
|
||||
result: Some(vec![NuDataFrame::try_from_columns(
|
||||
vec![
|
||||
Column::new(
|
||||
"ab".to_string(),
|
||||
vec![UntaggedValue::int(1).into(), UntaggedValue::int(3).into()],
|
||||
),
|
||||
Column::new(
|
||||
"b".to_string(),
|
||||
vec![UntaggedValue::int(2).into(), UntaggedValue::int(4).into()],
|
||||
),
|
||||
],
|
||||
&Span::default(),
|
||||
)
|
||||
.expect("simple df for test should not fail")
|
||||
.into_value(Tag::default())]),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let from: Tagged<String> = args.req(0)?;
|
||||
let to: Tagged<String> = args.req(1)?;
|
||||
|
||||
let (mut df, df_tag) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
df.as_mut()
|
||||
.rename(&from.item, &to.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
Ok(OutputStream::one(df.into_value(tag)))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::DataFrame;
|
||||
use super::ShellError;
|
||||
|
||||
#[test]
|
||||
fn examples_work_as_expected() -> Result<(), ShellError> {
|
||||
use crate::examples::test_dataframe as test_examples;
|
||||
|
||||
test_examples(DataFrame {})
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe select").rest(SyntaxShape::Any, "selected column names")
|
||||
Signature::build("dataframe select").rest("rest", SyntaxShape::Any, "selected column names")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -68,7 +68,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
})?;
|
||||
|
||||
let res = chunked
|
||||
.contains(pattern.as_str())
|
||||
.contains(&pattern.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![res.into_series()], &tag.span)?;
|
||||
|
@ -99,11 +99,11 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
));
|
||||
}
|
||||
|
||||
let cum_type = CumType::from_str(cum_type.item.as_str(), &cum_type.tag.span)?;
|
||||
let cum_type = CumType::from_str(&cum_type.item, &cum_type.tag.span)?;
|
||||
let mut res = match cum_type {
|
||||
CumType::Max => series.cum_max(reverse),
|
||||
CumType::Min => series.cum_min(reverse),
|
||||
CumType::Sum => series.cum_sum(reverse),
|
||||
CumType::Max => series.cummax(reverse),
|
||||
CumType::Min => series.cummin(reverse),
|
||||
CumType::Sum => series.cumsum(reverse),
|
||||
};
|
||||
|
||||
let name = format!("{}_{}", series.name(), cum_type.to_str());
|
||||
|
@ -60,7 +60,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let mut series = df.as_series(&df_tag.span)?;
|
||||
|
||||
series.rename(name.item.as_ref());
|
||||
series.rename(&name.item);
|
||||
|
||||
let df = NuDataFrame::try_from_series(vec![series], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
|
@ -77,7 +77,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
})?;
|
||||
|
||||
let mut res = chunked
|
||||
.replace(pattern.as_str(), replace.as_str())
|
||||
.replace(&pattern.item, &replace.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
res.rename(series.name());
|
||||
|
@ -77,7 +77,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
})?;
|
||||
|
||||
let mut res = chunked
|
||||
.replace_all(pattern.as_str(), replace.as_str())
|
||||
.replace_all(&pattern.item, &replace.item)
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &tag.span, None))?;
|
||||
|
||||
res.rename(series.name());
|
||||
|
@ -125,7 +125,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
));
|
||||
}
|
||||
|
||||
let roll_type = RollType::from_str(roll_type.item.as_str(), &roll_type.tag.span)?;
|
||||
let roll_type = RollType::from_str(&roll_type.item, &roll_type.tag.span)?;
|
||||
let res = match roll_type {
|
||||
RollType::Max => series.rolling_max(
|
||||
window_size.item as u32,
|
||||
|
@ -61,7 +61,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
.date64()
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &df_tag.span, None))?;
|
||||
|
||||
let res = casted.strftime(fmt.item.as_str()).into_series();
|
||||
let res = casted.strftime(&fmt.item).into_series();
|
||||
let df = NuDataFrame::try_from_series(vec![res], &tag.span)?;
|
||||
Ok(OutputStream::one(df.into_value(df_tag)))
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ impl WholeStreamCommand for DataFrame {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("dataframe sort")
|
||||
.switch("reverse", "invert sort", Some('r'))
|
||||
.rest(SyntaxShape::Any, "column names to sort dataframe")
|
||||
.rest("rest", SyntaxShape::Any, "column names to sort dataframe")
|
||||
}
|
||||
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
@ -64,14 +64,10 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let delimiter: Option<Tagged<String>> = args.get_flag("delimiter")?;
|
||||
let no_header: bool = args.has_flag("no_header");
|
||||
|
||||
let (mut df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let (df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
let mut file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::labeled_error(
|
||||
"Error with file name",
|
||||
format!("{}", e),
|
||||
&file_name.tag.span,
|
||||
)
|
||||
ShellError::labeled_error("Error with file name", e.to_string(), &file_name.tag.span)
|
||||
})?;
|
||||
|
||||
let writer = CsvWriter::new(&mut file);
|
||||
@ -103,7 +99,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
};
|
||||
|
||||
writer
|
||||
.finish(df.as_mut())
|
||||
.finish(df.as_ref())
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &file_name.tag.span, None))?;
|
||||
|
||||
let tagged_value = Value {
|
||||
|
@ -48,18 +48,14 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let tag = args.call_info.name_tag.clone();
|
||||
let file_name: Tagged<PathBuf> = args.req(0)?;
|
||||
|
||||
let (mut df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
let (df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
let file = File::create(&file_name.item).map_err(|e| {
|
||||
ShellError::labeled_error(
|
||||
"Error with file name",
|
||||
format!("{}", e),
|
||||
&file_name.tag.span,
|
||||
)
|
||||
ShellError::labeled_error("Error with file name", e.to_string(), &file_name.tag.span)
|
||||
})?;
|
||||
|
||||
ParquetWriter::new(file)
|
||||
.finish(df.as_mut())
|
||||
.finish(df.as_ref())
|
||||
.map_err(|e| parse_polars_error::<&str>(&e, &file_name.tag.span, None))?;
|
||||
|
||||
let tagged_value = Value {
|
||||
|
@ -46,30 +46,31 @@ pub(crate) fn parse_polars_error<T: AsRef<str>>(
|
||||
span: &Span,
|
||||
secondary: Option<T>,
|
||||
) -> ShellError {
|
||||
let (msg, label) = match e {
|
||||
PolarsError::PolarsArrowError(_) => ("PolarsArrow Error", format!("{}", e)),
|
||||
PolarsError::ArrowError(_) => ("Arrow Error", format!("{}", e)),
|
||||
PolarsError::InvalidOperation(_) => ("Invalid Operation", format!("{}", e)),
|
||||
PolarsError::DataTypeMisMatch(_) => ("Data Type Mismatch", format!("{}", e)),
|
||||
PolarsError::NotFound(_) => ("Not Found", format!("{}", e)),
|
||||
PolarsError::ShapeMisMatch(_) => ("Shape Mismatch", format!("{}", e)),
|
||||
PolarsError::Other(_) => ("Other", format!("{}", e)),
|
||||
PolarsError::OutOfBounds(_) => ("Out Of Bounds", format!("{}", e)),
|
||||
PolarsError::NoSlice => ("No Slice", format!("{}", e)),
|
||||
PolarsError::NoData(_) => ("No Data", format!("{}", e)),
|
||||
PolarsError::ValueError(_) => ("Value Error", format!("{}", e)),
|
||||
PolarsError::MemoryNotAligned => ("Memory Not Aligned", format!("{}", e)),
|
||||
PolarsError::ParquetError(_) => ("Parquet Error", format!("{}", e)),
|
||||
PolarsError::RandError(_) => ("Rand Error", format!("{}", e)),
|
||||
PolarsError::HasNullValues(_) => ("Has Null Values", format!("{}", e)),
|
||||
PolarsError::UnknownSchema(_) => ("Unknown Schema", format!("{}", e)),
|
||||
PolarsError::Various(_) => ("Various", format!("{}", e)),
|
||||
PolarsError::Io(_) => ("Io Error", format!("{}", e)),
|
||||
PolarsError::Regex(_) => ("Regex Error", format!("{}", e)),
|
||||
PolarsError::Duplicate(_) => ("Duplicate Error", format!("{}", e)),
|
||||
PolarsError::ImplementationError => ("Implementation Error", format!("{}", e)),
|
||||
let msg = match e {
|
||||
PolarsError::PolarsArrowError(_) => "PolarsArrow Error",
|
||||
PolarsError::ArrowError(_) => "Arrow Error",
|
||||
PolarsError::InvalidOperation(_) => "Invalid Operation",
|
||||
PolarsError::DataTypeMisMatch(_) => "Data Type Mismatch",
|
||||
PolarsError::NotFound(_) => "Not Found",
|
||||
PolarsError::ShapeMisMatch(_) => "Shape Mismatch",
|
||||
PolarsError::ComputeError(_) => "Computer error",
|
||||
PolarsError::OutOfBounds(_) => "Out Of Bounds",
|
||||
PolarsError::NoSlice => "No Slice",
|
||||
PolarsError::NoData(_) => "No Data",
|
||||
PolarsError::ValueError(_) => "Value Error",
|
||||
PolarsError::MemoryNotAligned => "Memory Not Aligned",
|
||||
PolarsError::RandError(_) => "Rand Error",
|
||||
PolarsError::HasNullValues(_) => "Has Null Values",
|
||||
PolarsError::UnknownSchema(_) => "Unknown Schema",
|
||||
PolarsError::Various(_) => "Various",
|
||||
PolarsError::Io(_) => "Io Error",
|
||||
PolarsError::Regex(_) => "Regex Error",
|
||||
PolarsError::Duplicate(_) => "Duplicate Error",
|
||||
PolarsError::ImplementationError => "Implementation Error",
|
||||
};
|
||||
|
||||
let label = e.to_string();
|
||||
|
||||
match secondary {
|
||||
None => ShellError::labeled_error(msg, label, span),
|
||||
Some(s) => ShellError::labeled_error_with_secondary(msg, label, span, s.as_ref(), span),
|
||||
|
@ -82,7 +82,7 @@ fn command(mut args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let mut series = df.as_series(&value.tag.span)?;
|
||||
|
||||
let series = series.rename(name.item.as_ref()).clone();
|
||||
let series = series.rename(&name.item).clone();
|
||||
|
||||
let (mut df, _) = NuDataFrame::try_from_stream(&mut args.input, &tag.span)?;
|
||||
|
||||
|
@ -31,12 +31,12 @@ impl WholeStreamCommand for AutoenvTrust {
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||
tag: _,
|
||||
}) => {
|
||||
let mut dir = fs::canonicalize(path)?;
|
||||
let mut dir = nu_path::canonicalize(path)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
_ => {
|
||||
let mut dir = fs::canonicalize(std::env::current_dir()?)?;
|
||||
let mut dir = nu_path::canonicalize(std::env::current_dir()?)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ impl WholeStreamCommand for AutoenvUntrust {
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref path)),
|
||||
tag: _,
|
||||
}) => {
|
||||
let mut dir = fs::canonicalize(path)?;
|
||||
let mut dir = nu_path::canonicalize(path)?;
|
||||
dir.push(".nu-env");
|
||||
dir
|
||||
}
|
||||
@ -61,7 +61,7 @@ impl WholeStreamCommand for AutoenvUntrust {
|
||||
let mut doc = String::new();
|
||||
file.read_to_string(&mut doc)?;
|
||||
|
||||
let mut allowed: Trusted = toml::from_str(doc.as_str()).unwrap_or_else(|_| Trusted::new());
|
||||
let mut allowed: Trusted = toml::from_str(&doc).unwrap_or_else(|_| Trusted::new());
|
||||
|
||||
let file_to_untrust = file_to_untrust.to_string_lossy().to_string();
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::{evaluate_baseline_expr, WholeStreamCommand};
|
||||
use nu_engine::{evaluate_baseline_expr, EnvVar, WholeStreamCommand};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{hir::CapturedBlock, hir::ClassifiedCommand, Signature, SyntaxShape};
|
||||
@ -90,9 +92,7 @@ pub fn set_env(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
|
||||
ctx.scope.exit_scope();
|
||||
|
||||
let value = value?;
|
||||
let value = value.as_string()?;
|
||||
|
||||
let value: EnvVar = value?.try_into()?;
|
||||
let name = name.item;
|
||||
|
||||
// Note: this is a special case for setting the context from a command
|
||||
|
13
crates/nu-command/src/commands/env/load_env.rs
vendored
13
crates/nu-command/src/commands/env/load_env.rs
vendored
@ -1,5 +1,7 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_engine::{EnvVar, WholeStreamCommand};
|
||||
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape, Value};
|
||||
@ -60,14 +62,17 @@ fn load_env_from_table(
|
||||
|
||||
for (key, value) in value.row_entries() {
|
||||
if key == "name" {
|
||||
var_name = Some(value.as_string()?);
|
||||
var_name = Some(value);
|
||||
} else if key == "value" {
|
||||
var_value = Some(value.as_string()?);
|
||||
var_value = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
match (var_name, var_value) {
|
||||
(Some(name), Some(value)) => ctx.scope.add_env_var(name, value),
|
||||
(Some(name), Some(value)) => {
|
||||
let env_var: EnvVar = value.try_into()?;
|
||||
ctx.scope.add_env_var(name.as_string()?, env_var);
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
r#"Expected each row in the table to have a "name" and "value" field."#,
|
||||
|
11
crates/nu-command/src/commands/env/with_env.rs
vendored
11
crates/nu-command/src/commands/env/with_env.rs
vendored
@ -1,5 +1,8 @@
|
||||
use std::convert::TryInto;
|
||||
|
||||
use crate::prelude::*;
|
||||
use nu_engine::run_block;
|
||||
use nu_engine::EnvVar;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
@ -73,20 +76,20 @@ fn with_env(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let variable: Value = args.req(0)?;
|
||||
let block: CapturedBlock = args.req(1)?;
|
||||
|
||||
let mut env = IndexMap::new();
|
||||
let mut env: IndexMap<String, EnvVar> = IndexMap::new();
|
||||
|
||||
match &variable.value {
|
||||
UntaggedValue::Table(table) => {
|
||||
if table.len() == 1 {
|
||||
// single row([[X W]; [Y Z]])
|
||||
for (k, v) in table[0].row_entries() {
|
||||
env.insert(k.clone(), v.convert_to_string());
|
||||
env.insert(k.clone(), v.try_into()?);
|
||||
}
|
||||
} else {
|
||||
// primitive values([X Y W Z])
|
||||
for row in table.chunks(2) {
|
||||
if row.len() == 2 && row[0].is_primitive() && row[1].is_primitive() {
|
||||
env.insert(row[0].convert_to_string(), row[1].convert_to_string());
|
||||
env.insert(row[0].convert_to_string(), (&row[1]).try_into()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,7 +97,7 @@ fn with_env(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
// when get object by `open x.json` or `from json`
|
||||
UntaggedValue::Row(row) => {
|
||||
for (k, v) in &row.entries {
|
||||
env.insert(k.clone(), v.convert_to_string());
|
||||
env.insert(k.clone(), v.try_into()?);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -12,6 +12,7 @@ impl WholeStreamCommand for Mkdir {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("mkdir")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::FilePath,
|
||||
"the name(s) of the path(s) to create",
|
||||
)
|
||||
|
@ -6,6 +6,7 @@ use log::debug;
|
||||
use nu_engine::StringOrBinary;
|
||||
use nu_engine::WholeStreamCommand;
|
||||
use nu_errors::ShellError;
|
||||
use nu_path::canonicalize;
|
||||
use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
|
||||
use nu_source::{AnchorLocation, Span, Tagged};
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -172,9 +173,9 @@ fn open(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
Ok(StringOrBinary::String(s)) => {
|
||||
ReturnSuccess::value(UntaggedValue::string(s).into_value(file_tag))
|
||||
}
|
||||
Ok(StringOrBinary::Binary(b)) => ReturnSuccess::value(
|
||||
UntaggedValue::binary(b.into_iter().collect()).into_value(file_tag),
|
||||
),
|
||||
Ok(StringOrBinary::Binary(b)) => {
|
||||
ReturnSuccess::value(UntaggedValue::binary(b).into_value(file_tag))
|
||||
}
|
||||
Err(se) => Err(se),
|
||||
}
|
||||
});
|
||||
@ -193,7 +194,7 @@ pub fn fetch(
|
||||
// TODO: I don't understand the point of this? Maybe for better error reporting
|
||||
let mut cwd = PathBuf::from(cwd);
|
||||
cwd.push(location);
|
||||
let nice_location = dunce::canonicalize(&cwd).map_err(|e| match e.kind() {
|
||||
let nice_location = canonicalize(&cwd).map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::NotFound => ShellError::labeled_error(
|
||||
format!("Cannot find file {:?}", cwd),
|
||||
"cannot find file",
|
||||
|
@ -26,7 +26,11 @@ impl WholeStreamCommand for Remove {
|
||||
)
|
||||
.switch("recursive", "delete subdirectories recursively", Some('r'))
|
||||
.switch("force", "suppress error when no file", Some('f'))
|
||||
.rest(SyntaxShape::GlobPattern, "the file path(s) to remove")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::GlobPattern,
|
||||
"the file path(s) to remove",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -142,6 +142,7 @@ impl WholeStreamCommand for Save {
|
||||
"treat values as-is rather than auto-converting based on file extension",
|
||||
Some('r'),
|
||||
)
|
||||
.switch("append", "append values rather than overriding", Some('a'))
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -165,6 +166,7 @@ fn save(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
let path: Option<Tagged<PathBuf>> = args.opt(0)?;
|
||||
let save_raw = args.has_flag("raw");
|
||||
let append = args.has_flag("append");
|
||||
|
||||
let input: Vec<Value> = args.input.collect();
|
||||
if path.is_none() {
|
||||
@ -231,7 +233,7 @@ fn save(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
};
|
||||
};
|
||||
|
||||
shell_manager.save(&full_path, &content?, name.span)
|
||||
shell_manager.save(&full_path, &content?, name.span, append)
|
||||
}
|
||||
|
||||
fn string_from(input: &[Value]) -> String {
|
||||
@ -239,7 +241,7 @@ fn string_from(input: &[Value]) -> String {
|
||||
|
||||
if !input.is_empty() {
|
||||
let mut first = true;
|
||||
for i in input.iter() {
|
||||
for i in input {
|
||||
if !first {
|
||||
save_data.push('\n');
|
||||
} else {
|
||||
|
@ -19,7 +19,7 @@ impl WholeStreamCommand for Touch {
|
||||
SyntaxShape::FilePath,
|
||||
"the path of the file you want to create",
|
||||
)
|
||||
.rest(SyntaxShape::FilePath, "additional files to create")
|
||||
.rest("rest", SyntaxShape::FilePath, "additional files to create")
|
||||
}
|
||||
fn usage(&self) -> &str {
|
||||
"Creates one or more files."
|
||||
@ -48,7 +48,7 @@ fn touch(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let target: Tagged<PathBuf> = args.req(0)?;
|
||||
let rest: Vec<Tagged<PathBuf>> = args.rest(1)?;
|
||||
|
||||
for item in vec![target].into_iter().chain(rest.into_iter()) {
|
||||
for item in vec![target].into_iter().chain(rest) {
|
||||
match OpenOptions::new().write(true).create(true).open(&item) {
|
||||
Ok(_) => continue,
|
||||
Err(err) => {
|
||||
|
@ -45,7 +45,7 @@ impl WholeStreamCommand for Command {
|
||||
|
||||
Ok(prepend
|
||||
.into_iter()
|
||||
.chain(args.input.into_iter().chain(vec![value]))
|
||||
.chain(args.input.into_iter().chain([value]))
|
||||
.into_output_stream())
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,11 @@ impl WholeStreamCommand for Compact {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("compact").rest(SyntaxShape::Any, "the columns to compact from the table")
|
||||
Signature::build("compact").rest(
|
||||
"rest",
|
||||
SyntaxShape::Any,
|
||||
"the columns to compact from the table",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -18,7 +18,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
SyntaxShape::Int,
|
||||
"the number of the row to drop",
|
||||
)
|
||||
.rest(SyntaxShape::Any, "Optionally drop more rows")
|
||||
.rest("rest", SyntaxShape::Any, "Optionally drop more rows")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -69,7 +69,7 @@ impl WholeStreamCommand for Each {
|
||||
}
|
||||
|
||||
pub fn process_row(
|
||||
captured_block: Arc<Box<CapturedBlock>>,
|
||||
captured_block: Arc<CapturedBlock>,
|
||||
context: Arc<EvaluationContext>,
|
||||
input: Value,
|
||||
external_redirection: ExternalRedirection,
|
||||
@ -96,7 +96,7 @@ pub fn process_row(
|
||||
|
||||
let result = run_block(
|
||||
&captured_block.block,
|
||||
&*context,
|
||||
&context,
|
||||
input_stream,
|
||||
external_redirection,
|
||||
);
|
||||
@ -121,13 +121,13 @@ fn each(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let block: CapturedBlock = args.req(0)?;
|
||||
let numbered: bool = args.has_flag("numbered");
|
||||
|
||||
let block = Arc::new(Box::new(block));
|
||||
let block = Arc::new(block);
|
||||
|
||||
if numbered {
|
||||
Ok(args
|
||||
.input
|
||||
.enumerate()
|
||||
.map(move |input| {
|
||||
.flat_map(move |input| {
|
||||
let block = block.clone();
|
||||
let context = context.clone();
|
||||
let row = make_indexed_item(input.0, input.1);
|
||||
@ -137,12 +137,11 @@ fn each(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Err(e) => OutputStream::one(Value::error(e)),
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.into_output_stream())
|
||||
} else {
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |input| {
|
||||
.flat_map(move |input| {
|
||||
let block = block.clone();
|
||||
let context = context.clone();
|
||||
|
||||
@ -151,7 +150,6 @@ fn each(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Err(e) => OutputStream::one(Value::error(e)),
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.into_output_stream())
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ impl WholeStreamCommand for EachGroup {
|
||||
|
||||
let group_size: Tagged<usize> = args.req(0)?;
|
||||
let block: CapturedBlock = args.req(1)?;
|
||||
let block = Arc::new(Box::new(block));
|
||||
let block = Arc::new(block);
|
||||
|
||||
let each_group_iterator = EachGroupIterator {
|
||||
block,
|
||||
@ -58,7 +58,7 @@ impl WholeStreamCommand for EachGroup {
|
||||
}
|
||||
|
||||
struct EachGroupIterator {
|
||||
block: Arc<Box<CapturedBlock>>,
|
||||
block: Arc<CapturedBlock>,
|
||||
context: Arc<EvaluationContext>,
|
||||
group_size: usize,
|
||||
input: InputStream,
|
||||
@ -96,7 +96,7 @@ impl Iterator for EachGroupIterator {
|
||||
|
||||
pub(crate) fn run_block_on_vec(
|
||||
input: Vec<Value>,
|
||||
block: Arc<Box<CapturedBlock>>,
|
||||
block: Arc<CapturedBlock>,
|
||||
context: Arc<EvaluationContext>,
|
||||
external_redirection: ExternalRedirection,
|
||||
) -> OutputStream {
|
||||
|
@ -49,7 +49,7 @@ impl WholeStreamCommand for EachWindow {
|
||||
let block: CapturedBlock = args.req(1)?;
|
||||
let stride: Option<Tagged<usize>> = args.get_flag("stride")?;
|
||||
|
||||
let block = Arc::new(Box::new(block));
|
||||
let block = Arc::new(block);
|
||||
|
||||
let mut window: Vec<_> = args
|
||||
.input
|
||||
@ -64,7 +64,7 @@ impl WholeStreamCommand for EachWindow {
|
||||
Ok(args
|
||||
.input
|
||||
.enumerate()
|
||||
.map(move |(i, input)| {
|
||||
.flat_map(move |(i, input)| {
|
||||
// This would probably be more efficient if `last` was a VecDeque
|
||||
// But we can't have that because it needs to be put into a Table
|
||||
window.remove(0);
|
||||
@ -86,7 +86,6 @@ impl WholeStreamCommand for EachWindow {
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.flatten()
|
||||
.map(Ok)
|
||||
.into_input_stream())
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ impl WholeStreamCommand for Command {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("empty?")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"the names of the columns to check emptiness",
|
||||
)
|
||||
@ -139,7 +140,7 @@ fn process_row(
|
||||
|
||||
let stream = run_block(
|
||||
&default_block.block,
|
||||
&*context,
|
||||
context,
|
||||
input_stream,
|
||||
ExternalRedirection::Stdout,
|
||||
);
|
||||
|
@ -14,7 +14,11 @@ impl WholeStreamCommand for Command {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("flatten").rest(SyntaxShape::String, "optionally flatten data by column")
|
||||
Signature::build("flatten").rest(
|
||||
"rest",
|
||||
SyntaxShape::String,
|
||||
"optionally flatten data by column",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -52,8 +56,7 @@ fn flatten(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
.map(move |item| flat_value(&columns, &item, &tag).into_iter())
|
||||
.flatten()
|
||||
.flat_map(move |item| flat_value(&columns, &item, &tag))
|
||||
.into_action_stream())
|
||||
}
|
||||
|
||||
@ -92,7 +95,7 @@ fn flat_value(
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k, v) in mapa.into_iter() {
|
||||
for (k, v) in mapa {
|
||||
if out.contains_key(k) {
|
||||
out.insert_value(format!("{}_{}", column, k), v.clone());
|
||||
} else {
|
||||
@ -155,7 +158,7 @@ fn flat_value(
|
||||
let mut expanded = vec![];
|
||||
|
||||
if let Some(TableInside::Entries(column, _, entries)) = a_table {
|
||||
for entry in entries.into_iter() {
|
||||
for entry in entries {
|
||||
let mut base = out.clone();
|
||||
base.insert_value(column, entry.clone());
|
||||
expanded.push(base.into_value());
|
||||
@ -166,7 +169,7 @@ fn flat_value(
|
||||
|
||||
expanded
|
||||
} else if item.is_table() {
|
||||
item.table_entries().map(Clone::clone).collect()
|
||||
item.table_entries().cloned().collect()
|
||||
} else {
|
||||
vec![item.clone()]
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ impl WholeStreamCommand for Command {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("get").rest(
|
||||
"rest",
|
||||
SyntaxShape::ColumnPath,
|
||||
"optionally return additional data by path",
|
||||
)
|
||||
@ -64,14 +65,12 @@ pub fn get(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
} else {
|
||||
trace!("get {:?}", column_paths);
|
||||
let output_stream = input
|
||||
.map(move |item| {
|
||||
.flat_map(move |item| {
|
||||
column_paths
|
||||
.iter()
|
||||
.map(move |path| get_output(&item, path))
|
||||
.flatten()
|
||||
.flat_map(move |path| get_output(&item, path))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.flatten()
|
||||
.into_action_stream();
|
||||
Ok(output_stream)
|
||||
}
|
||||
|
@ -137,10 +137,10 @@ pub fn group_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
value: UntaggedValue::Block(block_given),
|
||||
..
|
||||
}) => {
|
||||
let block = Arc::new(block_given);
|
||||
let block = Arc::new(*block_given);
|
||||
let error_key = "error";
|
||||
|
||||
for value in values.iter() {
|
||||
for value in &values {
|
||||
let run = block.clone();
|
||||
let context = context.clone();
|
||||
|
||||
|
@ -80,7 +80,7 @@ fn process_row(
|
||||
|
||||
let result = run_block(
|
||||
&block.block,
|
||||
&*context,
|
||||
&context,
|
||||
input_stream,
|
||||
ExternalRedirection::Stdout,
|
||||
);
|
||||
@ -162,7 +162,7 @@ fn insert(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
let column = Arc::new(column);
|
||||
|
||||
Ok(input
|
||||
.map(move |input| {
|
||||
.flat_map(move |input| {
|
||||
let context = context.clone();
|
||||
let value = value.clone();
|
||||
let column = column.clone();
|
||||
@ -172,6 +172,5 @@ fn insert(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
Err(e) => ActionStream::one(Err(e)),
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.into_action_stream())
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
ctx.scope.add_var(arg.name(), item.clone());
|
||||
}
|
||||
|
||||
let result = evaluate_baseline_expr(&*condition, &*ctx);
|
||||
let result = evaluate_baseline_expr(&condition, &ctx);
|
||||
ctx.scope.exit_scope();
|
||||
|
||||
!matches!(result, Ok(ref v) if v.is_true())
|
||||
|
@ -76,7 +76,7 @@ impl WholeStreamCommand for SubCommand {
|
||||
}
|
||||
trace!("ITEM = {:?}", item);
|
||||
|
||||
let result = evaluate_baseline_expr(&*condition, &*ctx);
|
||||
let result = evaluate_baseline_expr(&condition, &ctx);
|
||||
ctx.scope.exit_scope();
|
||||
trace!("RESULT = {:?}", result);
|
||||
|
||||
|
@ -36,6 +36,7 @@ mod skip;
|
||||
pub(crate) mod sort_by;
|
||||
mod uniq;
|
||||
mod update;
|
||||
mod update_cells;
|
||||
mod where_;
|
||||
mod wrap;
|
||||
mod zip_;
|
||||
@ -78,6 +79,7 @@ pub use skip::{Skip, SkipUntil, SkipWhile};
|
||||
pub use sort_by::SortBy;
|
||||
pub use uniq::Uniq;
|
||||
pub use update::Command as Update;
|
||||
pub use update_cells::SubCommand as UpdateCells;
|
||||
pub use where_::Command as Where;
|
||||
pub use wrap::Wrap;
|
||||
pub use zip_::Command as Zip;
|
||||
|
@ -14,7 +14,7 @@ impl WholeStreamCommand for Command {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("move")
|
||||
.rest(SyntaxShape::ColumnPath, "the columns to move")
|
||||
.rest("rest", SyntaxShape::ColumnPath, "the columns to move")
|
||||
.named(
|
||||
"after",
|
||||
SyntaxShape::ColumnPath,
|
||||
@ -242,7 +242,7 @@ fn move_after(table: &Value, columns: &[String], from: &ColumnPath) -> Result<Va
|
||||
let mut insert = false;
|
||||
let mut inserted = false;
|
||||
|
||||
for name in columns_moved.into_iter() {
|
||||
for name in columns_moved {
|
||||
if let Some(name) = name {
|
||||
reordered_columns.push(Some(name.clone()));
|
||||
|
||||
@ -291,7 +291,7 @@ fn move_before(table: &Value, columns: &[String], from: &ColumnPath) -> Result<V
|
||||
let mut reordered_columns = vec![];
|
||||
let mut inserted = false;
|
||||
|
||||
for name in columns_moved.into_iter() {
|
||||
for name in columns_moved {
|
||||
if let Some(name) = name {
|
||||
if !inserted && name == from {
|
||||
for column in columns {
|
||||
|
@ -18,7 +18,7 @@ impl WholeStreamCommand for Nth {
|
||||
SyntaxShape::Int,
|
||||
"the number of the row to return",
|
||||
)
|
||||
.rest(SyntaxShape::Any, "Optionally return more rows")
|
||||
.rest("rest", SyntaxShape::Any, "Optionally return more rows")
|
||||
.switch("skip", "Skip the rows instead of selecting them", Some('s'))
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ impl WholeStreamCommand for Pivot {
|
||||
Some('i'),
|
||||
)
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::String,
|
||||
"the names to give columns once pivoted",
|
||||
)
|
||||
|
@ -163,7 +163,7 @@ fn reduce(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
|
||||
context.scope.enter_scope();
|
||||
context.scope.add_var("$acc", f);
|
||||
let result = process_row(block, &*context, row);
|
||||
let result = process_row(block, &context, row);
|
||||
context.scope.exit_scope();
|
||||
|
||||
// we make sure that result is an indexed item
|
||||
@ -201,7 +201,7 @@ fn reduce(args: CommandArgs) -> Result<ActionStream, ShellError> {
|
||||
|
||||
context.scope.enter_scope();
|
||||
context.scope.add_var("$acc", f);
|
||||
let result = process_row(block, &*context, row);
|
||||
let result = process_row(block, &context, row);
|
||||
context.scope.exit_scope();
|
||||
result
|
||||
})?
|
||||
|
@ -13,7 +13,11 @@ impl WholeStreamCommand for Reject {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("reject").rest(SyntaxShape::String, "the names of columns to remove")
|
||||
Signature::build("reject").rest(
|
||||
"rest",
|
||||
SyntaxShape::String,
|
||||
"the names of columns to remove",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -19,7 +19,11 @@ impl WholeStreamCommand for Rename {
|
||||
SyntaxShape::String,
|
||||
"the new name for the first column",
|
||||
)
|
||||
.rest(SyntaxShape::String, "the new name for additional columns")
|
||||
.rest(
|
||||
"rest",
|
||||
SyntaxShape::String,
|
||||
"the new name for additional columns",
|
||||
)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -59,14 +59,12 @@ pub fn roll(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
|
||||
Ok(args
|
||||
.input
|
||||
.map(move |value| {
|
||||
.flat_map(move |value| {
|
||||
let tag = value.tag();
|
||||
|
||||
roll_by(value, &options)
|
||||
.unwrap_or_else(|| vec![UntaggedValue::nothing().into_value(tag)])
|
||||
.into_iter()
|
||||
})
|
||||
.flatten()
|
||||
.into_output_stream())
|
||||
}
|
||||
|
||||
@ -84,8 +82,7 @@ fn roll_by(value: Value, options: &Arguments) -> Option<Vec<Value>> {
|
||||
let values_rotated = rotate(
|
||||
value
|
||||
.row_entries()
|
||||
.map(|(_, value)| value)
|
||||
.map(Clone::clone)
|
||||
.map(|(_, value)| value.clone())
|
||||
.collect::<Vec<_>>(),
|
||||
&options.by,
|
||||
direction,
|
||||
@ -94,7 +91,7 @@ fn roll_by(value: Value, options: &Arguments) -> Option<Vec<Value>> {
|
||||
if let Some(ref values) = values_rotated {
|
||||
let mut out = TaggedDictBuilder::new(&tag);
|
||||
|
||||
for (k, v) in columns.iter().zip(values.iter()) {
|
||||
for (k, v) in columns.iter().zip(values) {
|
||||
out.insert_value(k, v.clone());
|
||||
}
|
||||
|
||||
@ -104,7 +101,7 @@ fn roll_by(value: Value, options: &Arguments) -> Option<Vec<Value>> {
|
||||
None
|
||||
} else if value.is_table() {
|
||||
rotate(
|
||||
value.table_entries().map(Clone::clone).collect(),
|
||||
value.table_entries().cloned().collect(),
|
||||
&options.by,
|
||||
direction,
|
||||
)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user