mirror of
https://github.com/nushell/nushell
synced 2024-12-27 21:43:09 +00:00
Merge pull request #265 from jonathandturner/defer-evaluation
Defer evaluation - part 1
This commit is contained in:
commit
a38ae910ac
102 changed files with 2765 additions and 1163 deletions
|
@ -1,5 +1,5 @@
|
|||
variables:
|
||||
lkg-rust-nightly: "2019-07-04"
|
||||
lkg-rust-nightly: "2019-08-08"
|
||||
|
||||
trigger:
|
||||
- master
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
history.txt
|
||||
tests/fixtures/nuplayground
|
71
Cargo.lock
generated
71
Cargo.lock
generated
|
@ -73,6 +73,16 @@ dependencies = [
|
|||
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.13"
|
||||
|
@ -974,6 +984,26 @@ name = "futures"
|
|||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures-async-stream"
|
||||
version = "0.1.0-alpha.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures-async-stream-macro 0.1.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pin-project 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-async-stream-macro"
|
||||
version = "0.1.0-alpha.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel-preview"
|
||||
version = "0.3.0-alpha.17"
|
||||
|
@ -1864,6 +1894,7 @@ dependencies = [
|
|||
"adhoc_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ansi_term 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"async-trait 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byte-unit 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1880,6 +1911,7 @@ dependencies = [
|
|||
"dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum-utils 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"enum_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-async-stream 0.1.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-sink-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures_codec 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1916,7 +1948,6 @@ dependencies = [
|
|||
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde-hjson 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_ini 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1925,6 +1956,7 @@ dependencies = [
|
|||
"syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sys-info 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sysinfo 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2204,6 +2236,16 @@ dependencies = [
|
|||
"ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0-alpha.4"
|
||||
|
@ -2356,6 +2398,18 @@ dependencies = [
|
|||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.5.6"
|
||||
|
@ -3052,6 +3106,15 @@ dependencies = [
|
|||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
|
@ -3643,6 +3706,7 @@ dependencies = [
|
|||
"checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d"
|
||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
|
||||
"checksum async-trait 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "fe9bad189e61411cfbcc8822b4a2b1534983ee24295fc8460d6be53da1afad74"
|
||||
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||
"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b"
|
||||
"checksum backtrace 0.3.34 (registry+https://github.com/rust-lang/crates.io-index)" = "b5164d292487f037ece34ec0de2fcede2faa162f085dd96d2385ab81b12765ba"
|
||||
|
@ -3745,6 +3809,8 @@ dependencies = [
|
|||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869"
|
||||
"checksum futures-async-stream 0.1.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "11656e20f3c6e4a026757266461ffeb73d8c2fcbcc464fc6f9660d8d66452f32"
|
||||
"checksum futures-async-stream-macro 0.1.0-alpha.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bcb1eaa199281990734c14fdf5c22077ecd9f7fc2c24d7a37d796bd54dbb8f10"
|
||||
"checksum futures-channel-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "21c71ed547606de08e9ae744bb3c6d80f5627527ef31ecf2a7210d0e67bc8fae"
|
||||
"checksum futures-core-preview 0.3.0-alpha.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4b141ccf9b7601ef987f36f1c0d9522f76df3bba1cf2e63bfacccc044c4558f5"
|
||||
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
|
||||
|
@ -3863,6 +3929,7 @@ dependencies = [
|
|||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
|
||||
"checksum pin-project 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2714268752963de91be73ea2689c3c63d2389b14fad04d033923e20cb3a1d99a"
|
||||
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
|
||||
"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af"
|
||||
"checksum platforms 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cfec0daac55b13af394ceaaad095d17c790f77bdc9329264f06e49d6cd3206c"
|
||||
|
@ -3879,6 +3946,7 @@ dependencies = [
|
|||
"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d"
|
||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||
"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
|
||||
|
@ -3957,6 +4025,7 @@ dependencies = [
|
|||
"checksum syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e80b8831c5a543192ffc3727f01cf0e57579c6ac15558e3048bfb5708892167b"
|
||||
"checksum sys-info 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "76d6cf7b349b6a6daaf7a3797227e2f4108c8dd398e0aca7e29b9fb239948541"
|
||||
"checksum sysinfo 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ee7d12b854e48e680bf4b10856a7867e843845158fa8226e6c2f6cc38539cb01"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
|
||||
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
|
||||
|
|
|
@ -30,16 +30,17 @@ ordered-float = {version = "1.0.2", features = ["serde"]}
|
|||
prettyprint = "0.7.0"
|
||||
futures-preview = { version = "=0.3.0-alpha.17", features = ["compat", "io-compat"] }
|
||||
futures-sink-preview = "=0.3.0-alpha.17"
|
||||
futures-async-stream = "0.1.0-alpha.1"
|
||||
async-trait = "0.1.7"
|
||||
futures_codec = "0.2.5"
|
||||
term = "0.5.2"
|
||||
bytes = "0.4.12"
|
||||
log = "0.4.8"
|
||||
pretty_env_logger = "0.3.0"
|
||||
serde = "1.0.98"
|
||||
serde = { version = "1.0.98", features = ["derive"] }
|
||||
serde_json = "1.0.40"
|
||||
serde-hjson = "0.9.0"
|
||||
serde_yaml = "0.8"
|
||||
serde_derive = "1.0.98"
|
||||
serde_bytes = "0.11.1"
|
||||
getset = "0.0.7"
|
||||
logos = "0.10.0-rc2"
|
||||
|
@ -69,7 +70,7 @@ serde_ini = "0.2.0"
|
|||
subprocess = "0.1.18"
|
||||
sys-info = "0.5.7"
|
||||
mime = "0.3.13"
|
||||
regex = "1.2.0"
|
||||
regex = "1.2.1"
|
||||
pretty-hex = "0.1.0"
|
||||
neso = "0.5.0"
|
||||
rawkey = "0.1.2"
|
||||
|
@ -85,6 +86,7 @@ heim = "0.0.6"
|
|||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.6.1"
|
||||
tempdir = "0.3.7"
|
||||
|
||||
[lib]
|
||||
name = "nu"
|
||||
|
|
167
src/cli.rs
167
src/cli.rs
|
@ -1,20 +1,17 @@
|
|||
use crate::commands::autoview;
|
||||
use crate::commands::classified::SinkCommand;
|
||||
use crate::commands::classified::{
|
||||
ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalCommand, InternalCommand,
|
||||
StreamNext,
|
||||
};
|
||||
use crate::commands::command::sink;
|
||||
use crate::commands::plugin::JsonRpc;
|
||||
use crate::commands::plugin::{PluginCommand, PluginSink};
|
||||
use crate::commands::static_command;
|
||||
use crate::context::Context;
|
||||
crate use crate::errors::ShellError;
|
||||
use crate::evaluate::Scope;
|
||||
use crate::git::current_branch;
|
||||
use crate::object::Value;
|
||||
use crate::parser::registry;
|
||||
use crate::parser::registry::CommandConfig;
|
||||
use crate::parser::{Pipeline, PipelineElement, TokenNode};
|
||||
use crate::parser::registry::Signature;
|
||||
use crate::parser::{hir, Pipeline, PipelineElement, TokenNode};
|
||||
use crate::prelude::*;
|
||||
|
||||
use log::{debug, trace};
|
||||
|
@ -62,8 +59,7 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
|
|||
let mut input = String::new();
|
||||
match reader.read_line(&mut input) {
|
||||
Ok(_) => {
|
||||
let response =
|
||||
serde_json::from_str::<JsonRpc<Result<CommandConfig, ShellError>>>(&input);
|
||||
let response = serde_json::from_str::<JsonRpc<Result<Signature, ShellError>>>(&input);
|
||||
match response {
|
||||
Ok(jrpc) => match jrpc.params {
|
||||
Ok(params) => {
|
||||
|
@ -71,16 +67,16 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
|
|||
if params.is_filter {
|
||||
let fname = fname.to_string();
|
||||
let name = params.name.clone();
|
||||
context.add_commands(vec![Arc::new(PluginCommand::new(
|
||||
context.add_commands(vec![static_command(PluginCommand::new(
|
||||
name, fname, params,
|
||||
))]);
|
||||
Ok(())
|
||||
} else if params.is_sink {
|
||||
} else {
|
||||
let fname = fname.to_string();
|
||||
let name = params.name.clone();
|
||||
context.add_sinks(vec![Arc::new(PluginSink::new(name, fname, params))]);
|
||||
Ok(())
|
||||
} else {
|
||||
context.add_commands(vec![static_command(PluginSink::new(
|
||||
name, fname, params,
|
||||
))]);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -149,18 +145,18 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
use crate::commands::*;
|
||||
|
||||
context.add_commands(vec![
|
||||
command("ps", Box::new(ps::ps)),
|
||||
command("ls", Box::new(ls::ls)),
|
||||
command("cd", Box::new(cd::cd)),
|
||||
command("first", Box::new(first::first)),
|
||||
command("size", Box::new(size::size)),
|
||||
command("from-csv", Box::new(from_csv::from_csv)),
|
||||
command("pick", Box::new(pick::pick)),
|
||||
command("from-ini", Box::new(from_ini::from_ini)),
|
||||
command("from-csv", Box::new(from_csv::from_csv)),
|
||||
command("from-json", Box::new(from_json::from_json)),
|
||||
command("from-toml", Box::new(from_toml::from_toml)),
|
||||
command("from-xml", Box::new(from_xml::from_xml)),
|
||||
command("ps", Box::new(ps::ps)),
|
||||
command("ls", Box::new(ls::ls)),
|
||||
command("cd", Box::new(cd::cd)),
|
||||
command("size", Box::new(size::size)),
|
||||
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
||||
command("get", Box::new(get::get)),
|
||||
command("enter", Box::new(enter::enter)),
|
||||
command("n", Box::new(next::next)),
|
||||
command("p", Box::new(prev::prev)),
|
||||
|
@ -179,23 +175,22 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
command("to-yaml", Box::new(to_yaml::to_yaml)),
|
||||
command("sort-by", Box::new(sort_by::sort_by)),
|
||||
command("tags", Box::new(tags::tags)),
|
||||
Arc::new(Remove),
|
||||
Arc::new(Copycp),
|
||||
Arc::new(Open),
|
||||
Arc::new(Mkdir),
|
||||
Arc::new(Date),
|
||||
Arc::new(Where),
|
||||
Arc::new(Config),
|
||||
Arc::new(Exit),
|
||||
Arc::new(SkipWhile),
|
||||
]);
|
||||
|
||||
context.add_sinks(vec![
|
||||
sink("autoview", Box::new(autoview::autoview)),
|
||||
sink("clip", Box::new(clip::clip)),
|
||||
sink("table", Box::new(table::table)),
|
||||
sink("vtable", Box::new(vtable::vtable)),
|
||||
Arc::new(Save),
|
||||
static_command(Get),
|
||||
//static_command(Cd),
|
||||
static_command(Remove),
|
||||
static_command(Open),
|
||||
static_command(Where),
|
||||
static_command(Config),
|
||||
static_command(SkipWhile),
|
||||
static_command(Exit),
|
||||
static_command(Clip),
|
||||
static_command(Autoview),
|
||||
static_command(Copycp),
|
||||
static_command(Date),
|
||||
static_command(Mkdir),
|
||||
static_command(Save),
|
||||
static_command(Table),
|
||||
static_command(VTable),
|
||||
]);
|
||||
}
|
||||
let _ = load_plugins(&mut context);
|
||||
|
@ -351,16 +346,18 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
|||
.map_err(|err| (line.clone(), err))?;
|
||||
|
||||
match pipeline.commands.last() {
|
||||
Some(ClassifiedCommand::Sink(_)) => {}
|
||||
Some(ClassifiedCommand::External(_)) => {}
|
||||
_ => pipeline.commands.push(ClassifiedCommand::Sink(SinkCommand {
|
||||
command: sink("autoview", Box::new(autoview::autoview)),
|
||||
name_span: Span::unknown(),
|
||||
args: registry::Args {
|
||||
positional: None,
|
||||
named: None,
|
||||
},
|
||||
})),
|
||||
_ => pipeline
|
||||
.commands
|
||||
.push(ClassifiedCommand::Internal(InternalCommand {
|
||||
command: static_command(autoview::Autoview),
|
||||
name_span: Span::unknown(),
|
||||
args: hir::Call::new(
|
||||
Box::new(hir::Expression::synthetic_string("autoview")),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
})),
|
||||
}
|
||||
|
||||
let mut input = ClassifiedInputStream::new();
|
||||
|
@ -388,35 +385,23 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
|||
)
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Sink(SinkCommand { name_span, .. })), Some(_)) => {
|
||||
return LineResult::Error(line.clone(), ShellError::labeled_error("Commands like table, save, and autoview must come last in the pipeline", "must come last", name_span));
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Sink(left)), None) => {
|
||||
let input_vec: Vec<Tagged<Value>> = input.objects.into_vec().await;
|
||||
if let Err(err) = left.run(ctx, input_vec) {
|
||||
return LineResult::Error(line.clone(), err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
(
|
||||
Some(ClassifiedCommand::Internal(left)),
|
||||
Some(ClassifiedCommand::External(_)),
|
||||
) => match left.run(ctx, input).await {
|
||||
) => match left.run(ctx, input, Text::from(line)).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
},
|
||||
|
||||
(Some(ClassifiedCommand::Internal(left)), Some(_)) => {
|
||||
match left.run(ctx, input).await {
|
||||
match left.run(ctx, input, Text::from(line)).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
}
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Internal(left)), None) => {
|
||||
match left.run(ctx, input).await {
|
||||
match left.run(ctx, input, Text::from(line)).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
}
|
||||
|
@ -494,12 +479,11 @@ fn classify_command(
|
|||
match context.has_command(name) {
|
||||
true => {
|
||||
let command = context.get_command(name);
|
||||
let config = command.config();
|
||||
let scope = Scope::empty();
|
||||
let config = command.signature();
|
||||
|
||||
trace!(target: "nu::build_pipeline", "classifying {:?}", config);
|
||||
|
||||
let args = config.evaluate_args(call, context, &scope, source)?;
|
||||
let args: hir::Call = config.parse_args(call, context.registry(), source)?;
|
||||
|
||||
Ok(ClassifiedCommand::Internal(InternalCommand {
|
||||
command,
|
||||
|
@ -507,43 +491,28 @@ fn classify_command(
|
|||
args,
|
||||
}))
|
||||
}
|
||||
false => match context.has_sink(name) {
|
||||
true => {
|
||||
let command = context.get_sink(name);
|
||||
let config = command.config();
|
||||
let scope = Scope::empty();
|
||||
false => {
|
||||
let arg_list_strings: Vec<Tagged<String>> = match call.children() {
|
||||
//Some(args) => args.iter().map(|i| i.as_external_arg(source)).collect(),
|
||||
Some(args) => args
|
||||
.iter()
|
||||
.filter_map(|i| match i {
|
||||
TokenNode::Whitespace(_) => None,
|
||||
other => Some(Tagged::from_simple_spanned_item(
|
||||
other.as_external_arg(source),
|
||||
other.span(),
|
||||
)),
|
||||
})
|
||||
.collect(),
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
let args = config.evaluate_args(call, context, &scope, source)?;
|
||||
|
||||
Ok(ClassifiedCommand::Sink(SinkCommand {
|
||||
command,
|
||||
name_span: head.span().clone(),
|
||||
args,
|
||||
}))
|
||||
}
|
||||
false => {
|
||||
let arg_list_strings: Vec<Tagged<String>> = match call.children() {
|
||||
//Some(args) => args.iter().map(|i| i.as_external_arg(source)).collect(),
|
||||
Some(args) => args
|
||||
.iter()
|
||||
.filter_map(|i| match i {
|
||||
TokenNode::Whitespace(_) => None,
|
||||
other => Some(Tagged::from_simple_spanned_item(
|
||||
other.as_external_arg(source),
|
||||
other.span(),
|
||||
)),
|
||||
})
|
||||
.collect(),
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
Ok(ClassifiedCommand::External(ExternalCommand {
|
||||
name: name.to_string(),
|
||||
name_span: head.span().clone(),
|
||||
args: arg_list_strings,
|
||||
}))
|
||||
}
|
||||
},
|
||||
Ok(ClassifiedCommand::External(ExternalCommand {
|
||||
name: name.to_string(),
|
||||
name_span: head.span().clone(),
|
||||
args: arg_list_strings,
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ crate mod from_yaml;
|
|||
crate mod get;
|
||||
crate mod lines;
|
||||
crate mod ls;
|
||||
crate mod next;
|
||||
crate mod mkdir;
|
||||
crate mod next;
|
||||
crate mod open;
|
||||
crate mod pick;
|
||||
crate mod plugin;
|
||||
|
@ -49,14 +49,23 @@ crate mod trim;
|
|||
crate mod vtable;
|
||||
crate mod where_;
|
||||
|
||||
crate use command::command;
|
||||
crate use autoview::Autoview;
|
||||
//crate use cd::Cd;
|
||||
crate use clip::Clip;
|
||||
crate use command::{
|
||||
command, static_command, Command, CommandArgs, RawCommandArgs, StaticCommand,
|
||||
UnevaluatedCallInfo,
|
||||
};
|
||||
crate use config::Config;
|
||||
crate use cp::Copycp;
|
||||
crate use date::Date;
|
||||
crate use exit::Exit;
|
||||
crate use open::Open;
|
||||
crate use get::Get;
|
||||
crate use mkdir::Mkdir;
|
||||
crate use open::Open;
|
||||
crate use rm::Remove;
|
||||
crate use save::Save;
|
||||
crate use skip_while::SkipWhile;
|
||||
crate use table::Table;
|
||||
crate use vtable::VTable;
|
||||
crate use where_::Where;
|
||||
|
|
|
@ -1,31 +1,67 @@
|
|||
use crate::commands::command::SinkCommandArgs;
|
||||
use crate::commands::{RawCommandArgs, StaticCommand};
|
||||
use crate::errors::ShellError;
|
||||
use crate::format::GenericView;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
if args.input.len() > 0 {
|
||||
if let Tagged {
|
||||
item: Value::Binary(_),
|
||||
..
|
||||
} = args.input[0]
|
||||
{
|
||||
args.ctx.get_sink("binaryview").run(args)?;
|
||||
} else if is_single_text_value(&args.input) {
|
||||
args.ctx.get_sink("textview").run(args)?;
|
||||
} else if equal_shapes(&args.input) {
|
||||
args.ctx.get_sink("table").run(args)?;
|
||||
} else {
|
||||
let mut host = args.ctx.host.lock().unwrap();
|
||||
for i in args.input.iter() {
|
||||
let view = GenericView::new(&i);
|
||||
handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
host.stdout("");
|
||||
}
|
||||
}
|
||||
pub struct Autoview;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AutoviewArgs {}
|
||||
|
||||
impl StaticCommand for Autoview {
|
||||
fn name(&self) -> &str {
|
||||
"autoview"
|
||||
}
|
||||
|
||||
Ok(())
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process_raw(registry, autoview)?.run()
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("autoview")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn autoview(
|
||||
AutoviewArgs {}: AutoviewArgs,
|
||||
mut context: RunnableContext,
|
||||
raw: RawCommandArgs,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
Ok(OutputStream::new(async_stream_block! {
|
||||
let input = context.input.drain_vec().await;
|
||||
|
||||
if input.len() > 0 {
|
||||
if let Tagged {
|
||||
item: Value::Binary(_),
|
||||
..
|
||||
} = input[0usize]
|
||||
{
|
||||
let binary = context.expect_command("binaryview");
|
||||
let result = binary.run(raw.with_input(input), &context.commands).await.unwrap();
|
||||
result.collect::<Vec<_>>().await;
|
||||
} else if is_single_text_value(&input) {
|
||||
let text = context.expect_command("textview");
|
||||
let result = text.run(raw.with_input(input), &context.commands).await.unwrap();
|
||||
result.collect::<Vec<_>>().await;
|
||||
} else if equal_shapes(&input) {
|
||||
let table = context.expect_command("table");
|
||||
let result = table.run(raw.with_input(input), &context.commands).await.unwrap();
|
||||
result.collect::<Vec<_>>().await;
|
||||
} else {
|
||||
println!("TODO!")
|
||||
// TODO
|
||||
// let mut host = context.host.lock().unwrap();
|
||||
// for i in input.iter() {
|
||||
// let view = GenericView::new(&i);
|
||||
// handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
// host.stdout("");
|
||||
// }
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
fn equal_shapes(input: &Vec<Tagged<Value>>) -> bool {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
args.shell_manager.cd(args.call_info, args.input)
|
||||
pub fn cd(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = args.shell_manager.clone();
|
||||
let args = args.evaluate_once(registry)?;
|
||||
shell_manager.cd(args)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::commands::command::Sink;
|
||||
use crate::parser::{registry::Args, TokenNode};
|
||||
use crate::commands::Command;
|
||||
use crate::parser::{hir, TokenNode};
|
||||
use crate::prelude::*;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures::stream::StreamExt;
|
||||
|
@ -81,7 +81,6 @@ crate enum ClassifiedCommand {
|
|||
#[allow(unused)]
|
||||
Expr(TokenNode),
|
||||
Internal(InternalCommand),
|
||||
Sink(SinkCommand),
|
||||
External(ExternalCommand),
|
||||
}
|
||||
|
||||
|
@ -91,28 +90,15 @@ impl ClassifiedCommand {
|
|||
match self {
|
||||
ClassifiedCommand::Expr(token) => token.span(),
|
||||
ClassifiedCommand::Internal(internal) => internal.name_span.into(),
|
||||
ClassifiedCommand::Sink(sink) => sink.name_span.into(),
|
||||
ClassifiedCommand::External(external) => external.name_span.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate struct SinkCommand {
|
||||
crate command: Arc<dyn Sink>,
|
||||
crate name_span: Span,
|
||||
crate args: Args,
|
||||
}
|
||||
|
||||
impl SinkCommand {
|
||||
crate fn run(self, context: &mut Context, input: Vec<Tagged<Value>>) -> Result<(), ShellError> {
|
||||
context.run_sink(self.command, self.name_span.clone(), self.args, input)
|
||||
}
|
||||
}
|
||||
|
||||
crate struct InternalCommand {
|
||||
crate command: Arc<dyn Command>,
|
||||
crate command: Arc<Command>,
|
||||
crate name_span: Span,
|
||||
crate args: Args,
|
||||
crate args: hir::Call,
|
||||
}
|
||||
|
||||
impl InternalCommand {
|
||||
|
@ -120,23 +106,27 @@ impl InternalCommand {
|
|||
self,
|
||||
context: &mut Context,
|
||||
input: ClassifiedInputStream,
|
||||
source: Text,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
if log_enabled!(log::Level::Trace) {
|
||||
trace!(target: "nu::run::internal", "->");
|
||||
trace!(target: "nu::run::internal", "{}", self.command.name());
|
||||
trace!(target: "nu::run::internal", "{:?}", self.args.debug());
|
||||
trace!(target: "nu::run::internal", "{}", self.args.debug(&source));
|
||||
}
|
||||
|
||||
let objects: InputStream =
|
||||
trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects);
|
||||
|
||||
let result = context.run_command(
|
||||
self.command,
|
||||
self.name_span.clone(),
|
||||
context.source_map.clone(),
|
||||
self.args,
|
||||
objects,
|
||||
)?;
|
||||
let result = context
|
||||
.run_command(
|
||||
self.command,
|
||||
self.name_span.clone(),
|
||||
context.source_map.clone(),
|
||||
self.args,
|
||||
source,
|
||||
objects,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut result = result.values;
|
||||
|
||||
|
|
|
@ -1,25 +1,71 @@
|
|||
use crate::commands::command::SinkCommandArgs;
|
||||
use crate::commands::{CommandArgs, StaticCommand};
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::errors::{labelled, ShellError};
|
||||
use crate::prelude::*;
|
||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
use futures::stream::StreamExt;
|
||||
use futures_async_stream::async_stream_block;
|
||||
|
||||
pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
pub struct Clip;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ClipArgs {}
|
||||
|
||||
impl StaticCommand for Clip {
|
||||
fn name(&self) -> &str {
|
||||
"clip"
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, clip)?.run()
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("clip")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clip(
|
||||
ClipArgs {}: ClipArgs,
|
||||
RunnableContext { input, name, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let stream = async_stream_block! {
|
||||
let values: Vec<Tagged<Value>> = input.values.collect().await;
|
||||
|
||||
inner_clip(values, name).await;
|
||||
};
|
||||
|
||||
let stream: BoxStream<'static, ReturnValue> = stream.boxed();
|
||||
|
||||
Ok(OutputStream::from(stream))
|
||||
}
|
||||
|
||||
async fn inner_clip(input: Vec<Tagged<Value>>, name: Span) -> OutputStream {
|
||||
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
|
||||
let mut new_copy_data = String::new();
|
||||
|
||||
if args.input.len() > 0 {
|
||||
if input.len() > 0 {
|
||||
let mut first = true;
|
||||
for i in args.input.iter() {
|
||||
for i in input.iter() {
|
||||
if !first {
|
||||
new_copy_data.push_str("\n");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
let string = i.as_string().map_err(labelled(
|
||||
args.call_info.name_span,
|
||||
let s = i.as_string().map_err(labelled(
|
||||
name,
|
||||
"Given non-string data",
|
||||
"expected strings from pipeline",
|
||||
))?;
|
||||
));
|
||||
|
||||
let string: String = match s {
|
||||
Ok(string) => string,
|
||||
Err(err) => return OutputStream::one(Err(err)),
|
||||
};
|
||||
|
||||
new_copy_data.push_str(&string);
|
||||
}
|
||||
|
@ -27,5 +73,5 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
|||
|
||||
clip_context.set_contents(new_copy_data).unwrap();
|
||||
|
||||
Ok(())
|
||||
OutputStream::empty()
|
||||
}
|
||||
|
|
|
@ -1,16 +1,51 @@
|
|||
use crate::context::SourceMap;
|
||||
use crate::context::SpanSource;
|
||||
use crate::context::{SourceMap, SpanSource};
|
||||
use crate::errors::ShellError;
|
||||
use crate::evaluate::Scope;
|
||||
use crate::object::Value;
|
||||
use crate::parser::registry::{self, Args};
|
||||
use crate::parser::hir;
|
||||
use crate::parser::{registry, ConfigDeserializer};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct UnevaluatedCallInfo {
|
||||
pub args: hir::Call,
|
||||
pub source: Text,
|
||||
pub source_map: SourceMap,
|
||||
pub name_span: Span,
|
||||
}
|
||||
|
||||
impl ToDebug for UnevaluatedCallInfo {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
self.args.fmt_debug(f, source)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnevaluatedCallInfo {
|
||||
fn evaluate(
|
||||
self,
|
||||
registry: ®istry::CommandRegistry,
|
||||
scope: &Scope,
|
||||
) -> Result<CallInfo, ShellError> {
|
||||
let args = self.args.evaluate(registry, scope, &self.source)?;
|
||||
|
||||
Ok(CallInfo {
|
||||
args,
|
||||
source_map: self.source_map,
|
||||
name_span: self.name_span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct CallInfo {
|
||||
pub args: Args,
|
||||
pub args: registry::EvaluatedArgs,
|
||||
pub source_map: SourceMap,
|
||||
pub name_span: Span,
|
||||
}
|
||||
|
@ -18,19 +53,264 @@ pub struct CallInfo {
|
|||
#[derive(Getters)]
|
||||
#[get = "crate"]
|
||||
pub struct CommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host + Send>>,
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: CallInfo,
|
||||
pub call_info: UnevaluatedCallInfo,
|
||||
// pub host: Arc<Mutex<dyn Host + Send>>,
|
||||
// pub shell_manager: ShellManager,
|
||||
// pub call_info: CallInfo,
|
||||
pub input: InputStream,
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[get = "crate"]
|
||||
pub struct RawCommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: UnevaluatedCallInfo,
|
||||
}
|
||||
|
||||
impl RawCommandArgs {
|
||||
pub fn with_input(self, input: Vec<Tagged<Value>>) -> CommandArgs {
|
||||
CommandArgs {
|
||||
host: self.host,
|
||||
shell_manager: self.shell_manager,
|
||||
call_info: self.call_info,
|
||||
input: input.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToDebug for CommandArgs {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
self.call_info.fmt_debug(f, source)
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandArgs {
|
||||
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
|
||||
self.call_info.args.nth(pos)
|
||||
pub fn evaluate_once(
|
||||
self,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<EvaluatedStaticCommandArgs, ShellError> {
|
||||
let host = self.host.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let input = self.input;
|
||||
let call_info = self.call_info.evaluate(registry, &Scope::empty())?;
|
||||
|
||||
Ok(EvaluatedStaticCommandArgs::new(
|
||||
host,
|
||||
shell_manager,
|
||||
call_info,
|
||||
input,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn positional_iter(&self) -> impl Iterator<Item = &Tagged<Value>> {
|
||||
self.call_info.args.positional_iter()
|
||||
pub fn name_span(&self) -> Span {
|
||||
self.call_info.name_span
|
||||
}
|
||||
|
||||
pub fn process<'de, T: Deserialize<'de>>(
|
||||
self,
|
||||
registry: &CommandRegistry,
|
||||
callback: fn(T, RunnableContext) -> Result<OutputStream, ShellError>,
|
||||
) -> Result<RunnableArgs<T>, ShellError> {
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let source_map = self.call_info.source_map.clone();
|
||||
let host = self.host.clone();
|
||||
let args = self.evaluate_once(registry)?;
|
||||
let (input, args) = args.split();
|
||||
let name_span = args.call_info.name_span;
|
||||
let mut deserializer = ConfigDeserializer::from_call_node(args);
|
||||
|
||||
Ok(RunnableArgs {
|
||||
args: T::deserialize(&mut deserializer)?,
|
||||
context: RunnableContext {
|
||||
input: input,
|
||||
commands: registry.clone(),
|
||||
shell_manager,
|
||||
name: name_span,
|
||||
source_map,
|
||||
host,
|
||||
},
|
||||
callback,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_raw<'de, T: Deserialize<'de>>(
|
||||
self,
|
||||
registry: &CommandRegistry,
|
||||
callback: fn(T, RunnableContext, RawCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
) -> Result<RunnableRawArgs<T>, ShellError> {
|
||||
let raw_args = RawCommandArgs {
|
||||
host: self.host.clone(),
|
||||
shell_manager: self.shell_manager.clone(),
|
||||
call_info: self.call_info.clone(),
|
||||
};
|
||||
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let source_map = self.call_info.source_map.clone();
|
||||
let host = self.host.clone();
|
||||
let args = self.evaluate_once(registry)?;
|
||||
let (input, args) = args.split();
|
||||
let name_span = args.call_info.name_span;
|
||||
let mut deserializer = ConfigDeserializer::from_call_node(args);
|
||||
|
||||
Ok(RunnableRawArgs {
|
||||
args: T::deserialize(&mut deserializer)?,
|
||||
context: RunnableContext {
|
||||
input: input,
|
||||
commands: registry.clone(),
|
||||
shell_manager,
|
||||
name: name_span,
|
||||
source_map,
|
||||
host,
|
||||
},
|
||||
raw_args,
|
||||
callback,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnableContext {
|
||||
pub input: InputStream,
|
||||
pub shell_manager: ShellManager,
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub commands: CommandRegistry,
|
||||
pub source_map: SourceMap,
|
||||
pub name: Span,
|
||||
}
|
||||
|
||||
impl RunnableContext {
|
||||
pub fn cwd(&self) -> PathBuf {
|
||||
PathBuf::from(self.shell_manager.path())
|
||||
}
|
||||
|
||||
pub fn expect_command(&self, name: &str) -> Arc<Command> {
|
||||
self.commands
|
||||
.get_command(name)
|
||||
.expect(&format!("Expected command {}", name))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnableArgs<T> {
|
||||
args: T,
|
||||
context: RunnableContext,
|
||||
callback: fn(T, RunnableContext) -> Result<OutputStream, ShellError>,
|
||||
}
|
||||
|
||||
impl<T> RunnableArgs<T> {
|
||||
pub fn run(self) -> Result<OutputStream, ShellError> {
|
||||
(self.callback)(self.args, self.context)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnableRawArgs<T> {
|
||||
args: T,
|
||||
raw_args: RawCommandArgs,
|
||||
context: RunnableContext,
|
||||
callback: fn(T, RunnableContext, RawCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
}
|
||||
|
||||
impl<T> RunnableRawArgs<T> {
|
||||
pub fn run(self) -> Result<OutputStream, ShellError> {
|
||||
(self.callback)(self.args, self.context, self.raw_args)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EvaluatedStaticCommandArgs {
|
||||
pub args: EvaluatedCommandArgs,
|
||||
pub input: InputStream,
|
||||
}
|
||||
|
||||
impl Deref for EvaluatedStaticCommandArgs {
|
||||
type Target = EvaluatedCommandArgs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.args
|
||||
}
|
||||
}
|
||||
|
||||
impl EvaluatedStaticCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<Mutex<dyn Host>>,
|
||||
shell_manager: ShellManager,
|
||||
call_info: CallInfo,
|
||||
input: impl Into<InputStream>,
|
||||
) -> EvaluatedStaticCommandArgs {
|
||||
EvaluatedStaticCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
shell_manager,
|
||||
call_info,
|
||||
},
|
||||
input: input.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_span(&self) -> Span {
|
||||
self.args.call_info.name_span
|
||||
}
|
||||
|
||||
pub fn parts(self) -> (InputStream, registry::EvaluatedArgs) {
|
||||
let EvaluatedStaticCommandArgs { args, input } = self;
|
||||
|
||||
(input, args.call_info.args)
|
||||
}
|
||||
|
||||
pub fn split(self) -> (InputStream, EvaluatedCommandArgs) {
|
||||
let EvaluatedStaticCommandArgs { args, input } = self;
|
||||
|
||||
(input, args)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[get = "pub"]
|
||||
pub struct EvaluatedFilterCommandArgs {
|
||||
args: EvaluatedCommandArgs,
|
||||
#[allow(unused)]
|
||||
input: Tagged<Value>,
|
||||
}
|
||||
|
||||
impl Deref for EvaluatedFilterCommandArgs {
|
||||
type Target = EvaluatedCommandArgs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.args
|
||||
}
|
||||
}
|
||||
|
||||
impl EvaluatedFilterCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<Mutex<dyn Host>>,
|
||||
shell_manager: ShellManager,
|
||||
call_info: CallInfo,
|
||||
input: Tagged<Value>,
|
||||
) -> EvaluatedFilterCommandArgs {
|
||||
EvaluatedFilterCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
shell_manager,
|
||||
call_info,
|
||||
},
|
||||
input,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Getters, new)]
|
||||
#[get = "crate"]
|
||||
pub struct EvaluatedCommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub shell_manager: ShellManager,
|
||||
pub call_info: CallInfo,
|
||||
}
|
||||
|
||||
impl EvaluatedCommandArgs {
|
||||
pub fn call_args(&self) -> ®istry::EvaluatedArgs {
|
||||
&self.call_info.args
|
||||
}
|
||||
|
||||
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
|
||||
self.call_info.args.nth(pos)
|
||||
}
|
||||
|
||||
pub fn expect_nth(&self, pos: usize) -> Result<&Tagged<Value>, ShellError> {
|
||||
|
@ -45,18 +325,21 @@ impl CommandArgs {
|
|||
self.call_info.args.get(name)
|
||||
}
|
||||
|
||||
pub fn slice_from(&self, from: usize) -> Vec<Tagged<Value>> {
|
||||
let positional = &self.call_info.args.positional;
|
||||
|
||||
match positional {
|
||||
None => vec![],
|
||||
Some(list) => list[from..].to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn has(&self, name: &str) -> bool {
|
||||
self.call_info.args.has(name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SinkCommandArgs {
|
||||
pub ctx: Context,
|
||||
pub call_info: CallInfo,
|
||||
pub input: Vec<Tagged<Value>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum CommandAction {
|
||||
ChangePath(String),
|
||||
|
@ -102,84 +385,156 @@ impl ReturnSuccess {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Command {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError>;
|
||||
pub trait StaticCommand: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn config(&self) -> registry::CommandConfig {
|
||||
registry::CommandConfig {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError>;
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: true,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Sink {
|
||||
fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError>;
|
||||
fn name(&self) -> &str;
|
||||
pub enum Command {
|
||||
Static(Arc<dyn StaticCommand>),
|
||||
}
|
||||
|
||||
fn config(&self) -> registry::CommandConfig {
|
||||
registry::CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: true,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
impl Command {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
Command::Static(command) => command.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> Signature {
|
||||
match self {
|
||||
Command::Static(command) => command.signature(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
match self {
|
||||
Command::Static(command) => command.run(args, registry),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnCommand {
|
||||
#[allow(unused)]
|
||||
pub struct FnFilterCommand {
|
||||
name: String,
|
||||
func: Box<dyn Fn(CommandArgs) -> Result<OutputStream, ShellError>>,
|
||||
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
}
|
||||
|
||||
impl Command for FnCommand {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
(self.func)(args)
|
||||
}
|
||||
|
||||
impl StaticCommand for FnFilterCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let CommandArgs {
|
||||
host,
|
||||
shell_manager,
|
||||
call_info,
|
||||
input,
|
||||
} = args;
|
||||
|
||||
let host: Arc<Mutex<dyn Host>> = host.clone();
|
||||
let shell_manager = shell_manager.clone();
|
||||
let registry: registry::CommandRegistry = registry.clone();
|
||||
let func = self.func;
|
||||
|
||||
let result = input.values.map(move |it| {
|
||||
let registry = registry.clone();
|
||||
let call_info = match call_info
|
||||
.clone()
|
||||
.evaluate(®istry, &Scope::it_value(it.clone()))
|
||||
{
|
||||
Err(err) => return OutputStream::from(vec![Err(err)]).values,
|
||||
Ok(args) => args,
|
||||
};
|
||||
|
||||
let args =
|
||||
EvaluatedFilterCommandArgs::new(host.clone(), shell_manager.clone(), call_info, it);
|
||||
|
||||
match func(args) {
|
||||
Err(err) => return OutputStream::from(vec![Err(err)]).values,
|
||||
Ok(stream) => stream.values,
|
||||
}
|
||||
});
|
||||
|
||||
let result = result.flatten();
|
||||
let result: BoxStream<ReturnValue> = result.boxed();
|
||||
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnRawCommand {
|
||||
name: String,
|
||||
func: Box<
|
||||
dyn Fn(CommandArgs, ®istry::CommandRegistry) -> Result<OutputStream, ShellError>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>,
|
||||
}
|
||||
|
||||
impl StaticCommand for FnRawCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
(self.func)(args, registry)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn command(
|
||||
name: &str,
|
||||
func: Box<dyn Fn(CommandArgs) -> Result<OutputStream, ShellError>>,
|
||||
) -> Arc<dyn Command> {
|
||||
Arc::new(FnCommand {
|
||||
func: Box<
|
||||
dyn Fn(CommandArgs, ®istry::CommandRegistry) -> Result<OutputStream, ShellError>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>,
|
||||
) -> Arc<Command> {
|
||||
Arc::new(Command::Static(Arc::new(FnRawCommand {
|
||||
name: name.to_string(),
|
||||
func,
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
pub struct FnSink {
|
||||
name: String,
|
||||
func: Box<dyn Fn(SinkCommandArgs) -> Result<(), ShellError>>,
|
||||
pub fn static_command(command: impl StaticCommand + 'static) -> Arc<Command> {
|
||||
Arc::new(Command::Static(Arc::new(command)))
|
||||
}
|
||||
|
||||
impl Sink for FnSink {
|
||||
fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
(self.func)(args)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sink(
|
||||
#[allow(unused)]
|
||||
pub fn filter(
|
||||
name: &str,
|
||||
func: Box<dyn Fn(SinkCommandArgs) -> Result<(), ShellError>>,
|
||||
) -> Arc<dyn Sink> {
|
||||
Arc::new(FnSink {
|
||||
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
) -> Arc<Command> {
|
||||
Arc::new(Command::Static(Arc::new(FnFilterCommand {
|
||||
name: name.to_string(),
|
||||
func,
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
|
|
@ -1,51 +1,60 @@
|
|||
use crate::prelude::*;
|
||||
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::config;
|
||||
use crate::object::Value;
|
||||
use crate::object::{config, Value};
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{CommandConfig, NamedType};
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use crate::parser::registry::{self};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
pub struct Config;
|
||||
|
||||
impl Command for Config {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
config(args)
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
pub struct ConfigArgs {
|
||||
set: Option<(Tagged<String>, Tagged<Value>)>,
|
||||
get: Option<Tagged<String>>,
|
||||
clear: Tagged<bool>,
|
||||
remove: Option<Tagged<String>>,
|
||||
path: Tagged<bool>,
|
||||
}
|
||||
|
||||
impl StaticCommand for Config {
|
||||
fn name(&self) -> &str {
|
||||
"config"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
named.insert("set".to_string(), NamedType::Optional(SyntaxType::Any));
|
||||
named.insert("get".to_string(), NamedType::Optional(SyntaxType::Any));
|
||||
named.insert("clear".to_string(), NamedType::Switch);
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("config")
|
||||
.named("set", SyntaxType::Any)
|
||||
.named("get", SyntaxType::Any)
|
||||
.named("remove", SyntaxType::Any)
|
||||
.switch("clear")
|
||||
.switch("path")
|
||||
}
|
||||
|
||||
named.insert("remove".to_string(), NamedType::Optional(SyntaxType::Any));
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: true,
|
||||
is_filter: false,
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, config)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut result = crate::object::config::config(args.call_info.name_span)?;
|
||||
pub fn config(
|
||||
ConfigArgs {
|
||||
set,
|
||||
get,
|
||||
clear,
|
||||
remove,
|
||||
path,
|
||||
}: ConfigArgs,
|
||||
RunnableContext { name, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut result = crate::object::config::config(name)?;
|
||||
|
||||
trace!("{:#?}", args.call_info.args.positional);
|
||||
trace!("{:#?}", args.call_info.args.named);
|
||||
|
||||
if let Some(v) = args.get("get") {
|
||||
let key = v.as_string()?;
|
||||
if let Some(v) = get {
|
||||
let key = v.to_string();
|
||||
let value = result
|
||||
.get(&key)
|
||||
.ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?;
|
||||
|
@ -55,34 +64,50 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
);
|
||||
}
|
||||
|
||||
if let Some(v) = args.get("set") {
|
||||
if let Ok((key, value)) = v.as_pair() {
|
||||
result.insert(key.as_string()?.to_string(), value.clone());
|
||||
if let Some((key, value)) = set {
|
||||
result.insert(key.to_string(), value.clone());
|
||||
|
||||
config::write_config(&result)?;
|
||||
config::write_config(&result)?;
|
||||
|
||||
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||
Value::Object(result.into()),
|
||||
v.span()
|
||||
)]
|
||||
.from_input_stream());
|
||||
}
|
||||
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||
Value::Object(result.into()),
|
||||
value.span()
|
||||
)]
|
||||
.from_input_stream());
|
||||
}
|
||||
|
||||
if let Some(c) = args.get("clear") {
|
||||
if let Tagged {
|
||||
item: true,
|
||||
tag: Tag { span, .. },
|
||||
} = clear
|
||||
{
|
||||
result.clear();
|
||||
|
||||
config::write_config(&result)?;
|
||||
|
||||
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||
Value::Object(result.into()),
|
||||
c.span()
|
||||
span
|
||||
)]
|
||||
.from_input_stream());
|
||||
}
|
||||
|
||||
if let Some(v) = args.get("remove") {
|
||||
let key = v.as_string()?;
|
||||
if let Tagged {
|
||||
item: true,
|
||||
tag: Tag { span, .. },
|
||||
} = path
|
||||
{
|
||||
let path = config::config_path()?;
|
||||
|
||||
return Ok(stream![Tagged::from_simple_spanned_item(
|
||||
Value::Primitive(Primitive::Path(path)),
|
||||
span
|
||||
)]
|
||||
.from_input_stream());
|
||||
}
|
||||
|
||||
if let Some(v) = remove {
|
||||
let key = v.to_string();
|
||||
|
||||
if result.contains_key(&key) {
|
||||
result.remove(&key);
|
||||
|
@ -93,15 +118,9 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
)));
|
||||
}
|
||||
|
||||
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).simple_spanned(v)]);
|
||||
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).simple_spanned(v.span())]);
|
||||
return Ok(obj.from_input_stream());
|
||||
}
|
||||
|
||||
if args.len() == 0 {
|
||||
return Ok(
|
||||
vec![Value::Object(result.into()).simple_spanned(args.call_info.name_span)].into(),
|
||||
);
|
||||
}
|
||||
|
||||
Err(ShellError::string(format!("Unimplemented")))
|
||||
return Ok(vec![Value::Object(result.into()).simple_spanned(name)].into());
|
||||
}
|
||||
|
|
|
@ -1,33 +1,28 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{CommandConfig, NamedType, PositionalType};
|
||||
use crate::parser::registry::{CommandRegistry, Signature};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct Copycp;
|
||||
|
||||
impl Command for Copycp {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
cp(args)
|
||||
impl StaticCommand for Copycp {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
cp(args, registry)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"cp"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
named.insert("recursive".to_string(), NamedType::Switch);
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![PositionalType::mandatory("file", SyntaxType::Path)],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: false,
|
||||
is_filter: false,
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("cp")
|
||||
.named("file", SyntaxType::Any)
|
||||
.switch("recursive")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,10 +95,11 @@ impl FileStructure {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn cp(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let mut source = PathBuf::from(args.shell_manager.path());
|
||||
let mut destination = PathBuf::from(args.shell_manager.path());
|
||||
let name_span = args.call_info.name_span;
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
match args
|
||||
.nth(0)
|
||||
|
|
|
@ -3,34 +3,28 @@ use crate::object::{Dictionary, Value};
|
|||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Local, Utc};
|
||||
|
||||
use crate::parser::registry::{CommandConfig, NamedType};
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::parser::registry::Signature;
|
||||
use chrono::{Datelike, TimeZone, Timelike};
|
||||
use core::fmt::Display;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
pub struct Date;
|
||||
|
||||
impl Command for Date {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
date(args)
|
||||
impl StaticCommand for Date {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
date(args, registry)
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
"date"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
named.insert("utc".to_string(), NamedType::Switch);
|
||||
named.insert("local".to_string(), NamedType::Switch);
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: true,
|
||||
is_filter: false,
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("mkdir").switch("utc").switch("local")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +68,9 @@ where
|
|||
Tagged::from_simple_spanned_item(Value::Object(Dictionary::from(indexmap)), span)
|
||||
}
|
||||
|
||||
pub fn date(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn date(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
let mut date_out = VecDeque::new();
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
|
|
|
@ -2,7 +2,9 @@ use crate::commands::command::CommandAction;
|
|||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn enter(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
//TODO: We could also enter a value in the stream
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
|
|
|
@ -1,36 +1,31 @@
|
|||
use crate::commands::command::CommandAction;
|
||||
use crate::commands::command::{CommandAction, StaticCommand};
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::registry::{CommandConfig, NamedType};
|
||||
use crate::parser::registry::{CommandRegistry, Signature};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
pub struct Exit;
|
||||
|
||||
impl Command for Exit {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
exit(args)
|
||||
impl StaticCommand for Exit {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
exit(args, registry)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"exit"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
named.insert("now".to_string(), NamedType::Switch);
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: false,
|
||||
is_filter: false,
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("exit").switch("now")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn exit(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
if args.call_info.args.has("now") {
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
||||
} else {
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::parser::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
|
||||
// TODO: "Amount remaining" wrapper
|
||||
|
||||
pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn first(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"First requires an amount",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
args.name_span(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -25,7 +28,7 @@ pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
}
|
||||
};
|
||||
|
||||
let input = args.input;
|
||||
|
||||
Ok(OutputStream::from_input(input.values.take(amount as u64)))
|
||||
Ok(OutputStream::from_input(
|
||||
args.input.values.take(amount as u64),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -45,9 +45,10 @@ pub fn from_csv_string_to_value(
|
|||
Ok(Tagged::from_item(Value::List(rows), tag))
|
||||
}
|
||||
|
||||
pub fn from_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
|
|
|
@ -37,9 +37,11 @@ pub fn from_ini_string_to_value(
|
|||
Ok(convert_ini_top_to_nu_value(&v, tag))
|
||||
}
|
||||
|
||||
pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| {
|
||||
|
|
|
@ -43,9 +43,14 @@ pub fn from_json_string_to_value(
|
|||
Ok(convert_json_value_to_nu_value(&v, tag))
|
||||
}
|
||||
|
||||
pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_json(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| {
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::object::base::OF64;
|
|||
use crate::object::{Primitive, TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
pub fn convert_toml_value_to_nu_value(v: &toml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
|
||||
let tag = tag.into();
|
||||
|
||||
match v {
|
||||
|
@ -39,9 +39,14 @@ pub fn from_toml_string_to_value(
|
|||
Ok(convert_toml_value_to_nu_value(&v, tag))
|
||||
}
|
||||
|
||||
pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_toml(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| {
|
||||
|
|
|
@ -56,9 +56,10 @@ pub fn from_xml_string_to_value(
|
|||
Ok(from_document_to_value(&parsed, tag))
|
||||
}
|
||||
|
||||
pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| {
|
||||
|
|
|
@ -47,9 +47,13 @@ pub fn from_yaml_string_to_value(
|
|||
Ok(convert_yaml_value_to_nu_value(&v, tag))
|
||||
}
|
||||
|
||||
pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_yaml(
|
||||
args: CommandArgs,
|
||||
_registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| {
|
||||
|
|
|
@ -1,8 +1,33 @@
|
|||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
fn get_member(path: &str, span: Span, obj: &Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||
pub struct Get;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetArgs {
|
||||
rest: Vec<Tagged<String>>,
|
||||
}
|
||||
|
||||
impl StaticCommand for Get {
|
||||
fn name(&self) -> &str {
|
||||
"get"
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, get)?.run()
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("get").rest()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_member(path: &Tagged<String>, obj: &Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||
let mut current = obj;
|
||||
for p in path.split(".") {
|
||||
match current.get_data_by_key(p) {
|
||||
|
@ -11,7 +36,7 @@ fn get_member(path: &str, span: Span, obj: &Tagged<Value>) -> Result<Tagged<Valu
|
|||
return Err(ShellError::labeled_error(
|
||||
"Unknown field",
|
||||
"object missing field",
|
||||
span,
|
||||
path.span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -20,41 +45,21 @@ fn get_member(path: &str, span: Span, obj: &Tagged<Value>) -> Result<Tagged<Valu
|
|||
Ok(current.clone())
|
||||
}
|
||||
|
||||
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Get requires a field or field path",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let amount = args.expect_nth(0)?.as_i64();
|
||||
|
||||
pub fn get(
|
||||
GetArgs { rest: fields }: GetArgs,
|
||||
RunnableContext { input, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
// If it's a number, get the row instead of the column
|
||||
if let Ok(amount) = amount {
|
||||
return Ok(args
|
||||
.input
|
||||
.values
|
||||
.skip(amount as u64)
|
||||
.take(1)
|
||||
.from_input_stream());
|
||||
}
|
||||
// if let Some(amount) = amount {
|
||||
// return Ok(input.values.skip(amount as u64).take(1).from_input_stream());
|
||||
// }
|
||||
|
||||
let fields: Result<Vec<(String, Span)>, _> = args
|
||||
.positional_iter()
|
||||
.map(|a| (a.as_string().map(|x| (x, a.span()))))
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
|
||||
let stream = args
|
||||
.input
|
||||
let stream = input
|
||||
.values
|
||||
.map(move |item| {
|
||||
let mut result = VecDeque::new();
|
||||
for field in &fields {
|
||||
match get_member(&field.0, field.1, &item) {
|
||||
match get_member(field, &item) {
|
||||
Ok(Tagged {
|
||||
item: Value::List(l),
|
||||
..
|
||||
|
|
|
@ -5,9 +5,12 @@ use log::trace;
|
|||
|
||||
// TODO: "Amount remaining" wrapper
|
||||
|
||||
pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let input = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
let input: InputStream = trace_stream!(target: "nu::trace_stream::lines", "input" = input);
|
||||
|
||||
let stream = input
|
||||
.values
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
args.shell_manager.ls(args.call_info, args.input)
|
||||
pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = args.shell_manager.clone();
|
||||
let args = args.evaluate_once(registry)?;
|
||||
shell_manager.ls(args)
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ macro_rules! command {
|
|||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($number:tt)* }
|
||||
Rest {}
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
|
@ -36,13 +36,14 @@ macro_rules! command {
|
|||
pub struct $export;
|
||||
|
||||
impl Command for $export {
|
||||
fn run(&self, $args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn command($args: CommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> {
|
||||
fn run(&self, $args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
fn command($args: EvaluatedCommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> {
|
||||
let output = $body;
|
||||
|
||||
Ok(output.boxed().to_output_stream())
|
||||
}
|
||||
|
||||
let $args = $args.evaluate_once(registry)?;
|
||||
let tuple = ( $($extract ,)* );
|
||||
command( $args, tuple )
|
||||
}
|
||||
|
@ -51,8 +52,8 @@ macro_rules! command {
|
|||
stringify!($config_name)
|
||||
}
|
||||
|
||||
fn config(&self) -> $crate::parser::registry::CommandConfig {
|
||||
$crate::parser::registry::CommandConfig {
|
||||
fn config(&self) -> $crate::parser::registry::Signature {
|
||||
$crate::parser::registry::Signature {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![$($mandatory_positional)*],
|
||||
rest_positional: false,
|
||||
|
@ -81,7 +82,7 @@ macro_rules! command {
|
|||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { -- $param_name:ident : Switch , $($rest:tt)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
|
@ -101,7 +102,7 @@ macro_rules! command {
|
|||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
|
@ -131,7 +132,7 @@ macro_rules! command {
|
|||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { -- $param_name:ident : $param_kind:ty , $($rest:tt)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
|
@ -151,7 +152,7 @@ macro_rules! command {
|
|||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
|
@ -181,7 +182,7 @@ macro_rules! command {
|
|||
Named { $export:tt $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { -- $param_name:ident ? : $param_kind:ty , $($rest:tt)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
|
@ -201,7 +202,7 @@ macro_rules! command {
|
|||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* ],
|
||||
optional_positional: vec![ $($optional_positional)* ],
|
||||
|
@ -231,7 +232,7 @@ macro_rules! command {
|
|||
Named { $export:ident $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { $param_name:ident : Block , $($rest:tt)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
|
@ -254,7 +255,7 @@ macro_rules! command {
|
|||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory_block(
|
||||
stringify!($param_name)
|
||||
|
@ -286,7 +287,7 @@ macro_rules! command {
|
|||
Named { $export:ident $args:ident $body:block }
|
||||
Positional { $($positional_count:tt)* }
|
||||
Rest { $param_name:ident : $param_kind:ty , $($rest:tt)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name:tt,
|
||||
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
|
||||
optional_positional: vec![ $($optional_positional:tt)* ],
|
||||
|
@ -309,7 +310,7 @@ macro_rules! command {
|
|||
Named { $export $args $body }
|
||||
Positional { $($positional_count)* + 1 }
|
||||
Rest { $($rest)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory(
|
||||
stringify!($param_name), <$param_kind>::syntax_type()
|
||||
|
@ -340,7 +341,7 @@ macro_rules! command {
|
|||
Named { $export $args $body }
|
||||
Positional { 0 }
|
||||
Rest { $($command_rest)* }
|
||||
CommandConfig {
|
||||
Signature {
|
||||
name: $config_name,
|
||||
mandatory_positional: vec![],
|
||||
optional_positional: vec![],
|
||||
|
@ -376,11 +377,11 @@ macro_rules! command {
|
|||
// stringify!($name)
|
||||
// }
|
||||
|
||||
// fn config(&self) -> CommandConfig {
|
||||
// fn config(&self) -> Signature {
|
||||
// let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
// named.insert(stringify!($param).to_string(), NamedType::$kind);
|
||||
|
||||
// CommandConfig {
|
||||
// Signature {
|
||||
// name: self.name().to_string(),
|
||||
// mandatory_positional: vec![],
|
||||
// optional_positional: vec![],
|
||||
|
|
|
@ -1,36 +1,32 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{CommandConfig, NamedType, PositionalType};
|
||||
use crate::parser::registry::{CommandRegistry, Signature};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct Mkdir;
|
||||
|
||||
impl Command for Mkdir {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
mkdir(args)
|
||||
impl StaticCommand for Mkdir {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
mkdir(args, registry)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"mkdir"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![PositionalType::mandatory("file", SyntaxType::Path)],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: false,
|
||||
is_filter: false,
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("mkdir").named("file", SyntaxType::Any)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mkdir(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn mkdir(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
let mut full_path = PathBuf::from(args.shell_manager.path());
|
||||
|
||||
match &args.nth(0) {
|
||||
|
|
|
@ -2,6 +2,6 @@ use crate::commands::command::CommandAction;
|
|||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn next(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn next(_args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::NextShell))].into())
|
||||
}
|
||||
|
|
|
@ -1,62 +1,95 @@
|
|||
use crate::commands::StaticCommand;
|
||||
use crate::context::SpanSource;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Switch, Value};
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{self, Signature};
|
||||
use crate::prelude::*;
|
||||
use mime::Mime;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
|
||||
command! {
|
||||
Open as open(args, path: Tagged<PathBuf>, --raw: Switch,) {
|
||||
let span = args.call_info.name_span;
|
||||
pub struct Open;
|
||||
|
||||
let cwd = args
|
||||
.shell_manager.path();
|
||||
#[derive(Deserialize)]
|
||||
pub struct OpenArgs {
|
||||
path: Tagged<PathBuf>,
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
let full_path = PathBuf::from(cwd);
|
||||
impl StaticCommand for Open {
|
||||
fn name(&self) -> &str {
|
||||
"open"
|
||||
}
|
||||
|
||||
let path_str = path.to_str().ok_or(ShellError::type_error("Path", "invalid path".tagged(path.tag())))?;
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.required("path", SyntaxType::Path)
|
||||
.switch("raw")
|
||||
}
|
||||
|
||||
let (file_extension, contents, contents_tag, span_source) = fetch(&full_path, path_str, path.span())?;
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, run)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
let file_extension = if raw.is_present() {
|
||||
None
|
||||
} else {
|
||||
file_extension
|
||||
};
|
||||
fn run(
|
||||
OpenArgs { raw, path }: OpenArgs,
|
||||
RunnableContext {
|
||||
shell_manager,
|
||||
name,
|
||||
..
|
||||
}: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let cwd = PathBuf::from(shell_manager.path());
|
||||
let full_path = PathBuf::from(cwd);
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
let path_str = path.to_str().ok_or(ShellError::type_error(
|
||||
"Path",
|
||||
"invalid path".tagged(path.tag()),
|
||||
))?;
|
||||
|
||||
if let Some(uuid) = contents_tag.origin {
|
||||
// If we have loaded something, track its source
|
||||
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(uuid, span_source)))
|
||||
let (file_extension, contents, contents_tag, span_source) =
|
||||
fetch(&full_path, path_str, path.span())?;
|
||||
|
||||
let file_extension = if raw { None } else { file_extension };
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
|
||||
if let Some(uuid) = contents_tag.origin {
|
||||
// If we have loaded something, track its source
|
||||
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(
|
||||
uuid,
|
||||
span_source,
|
||||
)))
|
||||
}
|
||||
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(string)) => {
|
||||
let value = parse_as_value(file_extension, string, contents_tag, name)?;
|
||||
|
||||
match value {
|
||||
Tagged {
|
||||
item: Value::List(list),
|
||||
..
|
||||
} => {
|
||||
for elem in list {
|
||||
stream.push_back(ReturnSuccess::value(elem));
|
||||
}
|
||||
}
|
||||
x => stream.push_back(ReturnSuccess::value(x)),
|
||||
}
|
||||
}
|
||||
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(string)) => {
|
||||
let value = parse_as_value(
|
||||
file_extension,
|
||||
string,
|
||||
contents_tag,
|
||||
span,
|
||||
)?;
|
||||
other => stream.push_back(ReturnSuccess::value(other.tagged(contents_tag))),
|
||||
};
|
||||
|
||||
match value {
|
||||
Tagged { item: Value::List(list), .. } => {
|
||||
for elem in list {
|
||||
stream.push_back(ReturnSuccess::value(elem));
|
||||
}
|
||||
}
|
||||
x => stream.push_back(ReturnSuccess::value(x))
|
||||
}
|
||||
},
|
||||
|
||||
other => stream.push_back(ReturnSuccess::value(other.tagged(contents_tag))),
|
||||
};
|
||||
|
||||
stream
|
||||
}
|
||||
Ok(stream.boxed().to_output_stream())
|
||||
}
|
||||
|
||||
pub fn fetch(
|
||||
|
|
|
@ -1,19 +1,30 @@
|
|||
use crate::context::CommandRegistry;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::base::select_fields;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
pub fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let len = args.len();
|
||||
let span = args.name_span();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Pick requires fields",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields: Result<Vec<String>, _> = args
|
||||
.positional
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| a.as_string())
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
let input = args.input;
|
||||
|
||||
let objects = input
|
||||
.values
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::registry;
|
||||
use crate::prelude::*;
|
||||
|
@ -37,41 +38,34 @@ pub enum NuResult {
|
|||
pub struct PluginCommand {
|
||||
name: String,
|
||||
path: String,
|
||||
config: registry::CommandConfig,
|
||||
config: registry::Signature,
|
||||
}
|
||||
|
||||
impl Command for PluginCommand {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
filter_plugin(self.path.clone(), args)
|
||||
}
|
||||
impl StaticCommand for PluginCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
fn config(&self) -> registry::CommandConfig {
|
||||
|
||||
fn signature(&self) -> registry::Signature {
|
||||
self.config.clone()
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
filter_plugin(self.path.clone(), args, registry)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct PluginSink {
|
||||
name: String,
|
||||
pub fn filter_plugin(
|
||||
path: String,
|
||||
config: registry::CommandConfig,
|
||||
}
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
impl Sink for PluginSink {
|
||||
fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
sink_plugin(self.path.clone(), args)
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
fn config(&self) -> registry::CommandConfig {
|
||||
self.config.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut child = std::process::Command::new(path)
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
|
@ -84,7 +78,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||
let mut eos: VecDeque<Tagged<Value>> = VecDeque::new();
|
||||
eos.push_back(Value::Primitive(Primitive::EndOfStream).tagged_unknown());
|
||||
|
||||
let call_info = args.call_info;
|
||||
let call_info = args.call_info.clone();
|
||||
|
||||
let stream = bos
|
||||
.chain(args.input.values)
|
||||
|
@ -238,20 +232,55 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
|||
Ok(stream.to_output_stream())
|
||||
}
|
||||
|
||||
pub fn sink_plugin(path: String, args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
//use subprocess::Exec;
|
||||
let request = JsonRpc::new("sink", (args.call_info, args.input));
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
let mut tmpfile = tempfile::NamedTempFile::new()?;
|
||||
let _ = writeln!(tmpfile, "{}", request_raw);
|
||||
let _ = tmpfile.flush();
|
||||
|
||||
let mut child = std::process::Command::new(path)
|
||||
.arg(tmpfile.path())
|
||||
.spawn()
|
||||
.expect("Failed to spawn child process");
|
||||
|
||||
let _ = child.wait();
|
||||
|
||||
Ok(())
|
||||
#[derive(new)]
|
||||
pub struct PluginSink {
|
||||
name: String,
|
||||
path: String,
|
||||
config: registry::Signature,
|
||||
}
|
||||
|
||||
impl StaticCommand for PluginSink {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn signature(&self) -> registry::Signature {
|
||||
self.config.clone()
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
sink_plugin(self.path.clone(), args, registry)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sink_plugin(
|
||||
path: String,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
//use subprocess::Exec;
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let call_info = args.call_info.clone();
|
||||
|
||||
let stream = async_stream_block! {
|
||||
let input: Vec<Tagged<Value>> = args.input.values.collect().await;
|
||||
|
||||
let request = JsonRpc::new("sink", (call_info.clone(), input));
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
let mut tmpfile = tempfile::NamedTempFile::new().unwrap();
|
||||
let _ = writeln!(tmpfile, "{}", request_raw);
|
||||
let _ = tmpfile.flush();
|
||||
|
||||
let mut child = std::process::Command::new(path)
|
||||
.arg(tmpfile.path())
|
||||
.spawn()
|
||||
.expect("Failed to spawn child process");
|
||||
|
||||
let _ = child.wait();
|
||||
};
|
||||
Ok(OutputStream::new(stream))
|
||||
}
|
||||
|
|
|
@ -2,6 +2,6 @@ use crate::commands::command::CommandAction;
|
|||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn prev(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn prev(_args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::PreviousShell))].into())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::object::process::process_dict;
|
|||
use crate::prelude::*;
|
||||
use sysinfo::{RefreshKind, SystemExt};
|
||||
|
||||
pub fn ps(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn ps(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let mut system = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes());
|
||||
system.refresh_processes();
|
||||
let list = system.get_process_list();
|
||||
|
|
|
@ -2,20 +2,30 @@ use crate::errors::ShellError;
|
|||
use crate::object::base::reject_fields;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let len = args.len();
|
||||
let span = args.name_span();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Reject requires fields",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields: Result<Vec<String>, _> = args
|
||||
.positional
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| a.as_string())
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
|
||||
let stream = args
|
||||
.input
|
||||
let stream = input
|
||||
.values
|
||||
.map(move |item| reject_fields(&item, &fields, item.tag()).into_tagged_value());
|
||||
|
||||
|
|
|
@ -1,47 +1,46 @@
|
|||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{CommandConfig, NamedType, PositionalType};
|
||||
use crate::prelude::*;
|
||||
|
||||
use glob::glob;
|
||||
use indexmap::IndexMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub struct Remove;
|
||||
|
||||
impl Command for Remove {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
rm(args)
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
pub struct RemoveArgs {
|
||||
path: Tagged<PathBuf>,
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
impl StaticCommand for Remove {
|
||||
fn name(&self) -> &str {
|
||||
"rm"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
named.insert("recursive".to_string(), NamedType::Switch);
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("rm")
|
||||
.required("path", SyntaxType::Path)
|
||||
.switch("recursive")
|
||||
}
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![PositionalType::mandatory("file", SyntaxType::Path)],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: false,
|
||||
is_filter: false,
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, rm)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rm(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = PathBuf::from(args.shell_manager.path());
|
||||
pub fn rm(
|
||||
RemoveArgs { path, recursive }: RemoveArgs,
|
||||
context: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = context.cwd();
|
||||
|
||||
match args
|
||||
.nth(0)
|
||||
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||
.as_string()?
|
||||
.as_str()
|
||||
{
|
||||
match path.item.to_str().unwrap() {
|
||||
"." | ".." => return Err(ShellError::string("\".\" and \"..\" may not be removed")),
|
||||
file => full_path.push(file),
|
||||
}
|
||||
|
@ -58,11 +57,11 @@ pub fn rm(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
match entry {
|
||||
Ok(path) => {
|
||||
if path.is_dir() {
|
||||
if !args.has("recursive") {
|
||||
if !recursive {
|
||||
return Err(ShellError::labeled_error(
|
||||
"is a directory",
|
||||
"is a directory",
|
||||
args.call_info.name_span,
|
||||
context.name,
|
||||
));
|
||||
}
|
||||
std::fs::remove_dir_all(&path).expect("can not remove directory");
|
||||
|
|
|
@ -1,157 +1,215 @@
|
|||
use crate::commands::command::SinkCommandArgs;
|
||||
use crate::commands::to_csv::{to_string as to_csv_to_string, value_to_csv_value};
|
||||
use crate::commands::to_json::value_to_json_value;
|
||||
use crate::commands::to_toml::value_to_toml_value;
|
||||
use crate::commands::to_yaml::value_to_yaml_value;
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::parser::registry::{CommandConfig, NamedType};
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
use crate::SpanSource;
|
||||
use indexmap::IndexMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct Save;
|
||||
|
||||
impl Sink for Save {
|
||||
fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
save(args)
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
pub struct SaveArgs {
|
||||
path: Option<Tagged<PathBuf>>,
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
impl StaticCommand for Save {
|
||||
fn name(&self) -> &str {
|
||||
"save"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||
named.insert("raw".to_string(), NamedType::Switch);
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("save")
|
||||
.optional("path", SyntaxType::Path)
|
||||
.switch("raw")
|
||||
}
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: false,
|
||||
is_filter: false,
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, save)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
let cwd = args.ctx.shell_manager.path();
|
||||
let mut full_path = PathBuf::from(cwd);
|
||||
pub fn save(
|
||||
SaveArgs {
|
||||
path,
|
||||
raw: save_raw,
|
||||
}: SaveArgs,
|
||||
context: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = context.cwd();
|
||||
|
||||
let save_raw = if args.call_info.args.has("raw") {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if args.call_info.args.positional.is_none() {
|
||||
// If there is no filename, check the metadata for the origin filename
|
||||
if args.input.len() > 0 {
|
||||
let origin = args.input[0].origin();
|
||||
match origin.map(|x| args.call_info.source_map.get(&x)).flatten() {
|
||||
Some(path) => match path {
|
||||
SpanSource::File(file) => {
|
||||
full_path.push(Path::new(file));
|
||||
}
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
if path.is_none() {
|
||||
let source_map = context.source_map.clone();
|
||||
let stream = async_stream_block! {
|
||||
let input: Vec<Tagged<Value>> = context.input.values.collect().await;
|
||||
// If there is no filename, check the metadata for the origin filename
|
||||
if input.len() > 0 {
|
||||
let origin = input[0].origin();
|
||||
match origin.map(|x| source_map.get(&x)).flatten() {
|
||||
Some(path) => match path {
|
||||
SpanSource::File(file) => {
|
||||
full_path.push(Path::new(file));
|
||||
}
|
||||
_ => {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Save requires a filepath",
|
||||
"needs path",
|
||||
context.name,
|
||||
));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Save requires a filepath",
|
||||
"needs path",
|
||||
args.call_info.name_span,
|
||||
context.name,
|
||||
));
|
||||
}
|
||||
},
|
||||
None => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Save requires a filepath",
|
||||
"needs path",
|
||||
args.call_info.name_span,
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Save requires a filepath",
|
||||
"needs path",
|
||||
args.call_info.name_span,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
let arg = &args.call_info.args.positional.unwrap()[0];
|
||||
let arg_span = arg.span();
|
||||
match arg.item {
|
||||
Value::Primitive(Primitive::String(ref s)) => full_path.push(Path::new(s)),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Save requires a string as a filepath",
|
||||
} else {
|
||||
yield Err(ShellError::labeled_error(
|
||||
"Save requires a filepath",
|
||||
"needs path",
|
||||
arg_span.clone(),
|
||||
context.name,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let contents = match full_path.extension() {
|
||||
Some(x) if x == "csv" && !save_raw => {
|
||||
if args.input.len() != 1 {
|
||||
return Err(ShellError::string(
|
||||
"saving to csv requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
to_csv_to_string(&value_to_csv_value(&args.input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "toml" && !save_raw => {
|
||||
if args.input.len() != 1 {
|
||||
return Err(ShellError::string(
|
||||
"saving to toml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
toml::to_string(&value_to_toml_value(&args.input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "json" && !save_raw => {
|
||||
if args.input.len() != 1 {
|
||||
return Err(ShellError::string(
|
||||
"saving to json requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_json::to_string(&value_to_json_value(&args.input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "yml" && !save_raw => {
|
||||
if args.input.len() != 1 {
|
||||
return Err(ShellError::string(
|
||||
"saving to yml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_yaml::to_string(&value_to_yaml_value(&args.input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "yaml" && !save_raw => {
|
||||
if args.input.len() != 1 {
|
||||
return Err(ShellError::string(
|
||||
"saving to yaml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_yaml::to_string(&value_to_yaml_value(&args.input[0])).unwrap()
|
||||
}
|
||||
_ => {
|
||||
let mut save_data = String::new();
|
||||
if args.input.len() > 0 {
|
||||
let mut first = true;
|
||||
for i in args.input.iter() {
|
||||
if !first {
|
||||
save_data.push_str("\n");
|
||||
} else {
|
||||
first = false;
|
||||
let contents = match full_path.extension() {
|
||||
Some(x) if x == "csv" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to csv requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
save_data.push_str(&i.as_string().unwrap());
|
||||
to_csv_to_string(&value_to_csv_value(&input[0])).unwrap()
|
||||
}
|
||||
}
|
||||
save_data
|
||||
}
|
||||
};
|
||||
Some(x) if x == "toml" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to toml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
toml::to_string(&value_to_toml_value(&input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "json" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to json requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_json::to_string(&value_to_json_value(&input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "yml" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to yml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "yaml" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to yaml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
||||
}
|
||||
_ => {
|
||||
let mut save_data = String::new();
|
||||
if input.len() > 0 {
|
||||
let mut first = true;
|
||||
for i in input.iter() {
|
||||
if !first {
|
||||
save_data.push_str("\n");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
save_data.push_str(&i.as_string().unwrap());
|
||||
}
|
||||
}
|
||||
save_data
|
||||
}
|
||||
};
|
||||
|
||||
let _ = std::fs::write(full_path, contents);
|
||||
Ok(())
|
||||
let _ = std::fs::write(full_path, contents);
|
||||
};
|
||||
|
||||
Ok(OutputStream::new(stream))
|
||||
} else {
|
||||
full_path.push(path.unwrap().item());
|
||||
|
||||
let stream = async_stream_block! {
|
||||
let input: Vec<Tagged<Value>> = context.input.values.collect().await;
|
||||
|
||||
let contents = match full_path.extension() {
|
||||
Some(x) if x == "csv" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to csv requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
to_csv_to_string(&value_to_csv_value(&input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "toml" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to toml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
toml::to_string(&value_to_toml_value(&input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "json" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to json requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_json::to_string(&value_to_json_value(&input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "yml" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to yml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
||||
}
|
||||
Some(x) if x == "yaml" && !save_raw => {
|
||||
if input.len() != 1 {
|
||||
yield Err(ShellError::string(
|
||||
"saving to yaml requires a single object (or use --raw)",
|
||||
));
|
||||
}
|
||||
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
|
||||
}
|
||||
_ => {
|
||||
let mut save_data = String::new();
|
||||
if input.len() > 0 {
|
||||
let mut first = true;
|
||||
for i in input.iter() {
|
||||
if !first {
|
||||
save_data.push_str("\n");
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
save_data.push_str(&i.as_string().unwrap());
|
||||
}
|
||||
}
|
||||
save_data
|
||||
}
|
||||
};
|
||||
|
||||
let _ = std::fs::write(full_path, contents);
|
||||
};
|
||||
|
||||
Ok(OutputStream::new(stream))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
|||
use crate::object::TaggedDictBuilder;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn shells(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let mut shells_out = VecDeque::new();
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
|||
use crate::object::{TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn size(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
Ok(input
|
||||
|
|
|
@ -1,44 +1,40 @@
|
|||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::registry::CommandConfig;
|
||||
use crate::parser::registry::PositionalType;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct SkipWhile;
|
||||
|
||||
impl Command for SkipWhile {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
skip_while(args)
|
||||
}
|
||||
#[derive(Deserialize)]
|
||||
pub struct SkipWhileArgs {
|
||||
condition: value::Block,
|
||||
}
|
||||
|
||||
impl StaticCommand for SkipWhile {
|
||||
fn name(&self) -> &str {
|
||||
"skip-while"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![PositionalType::mandatory_block("condition")],
|
||||
rest_positional: false,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("skip-while")
|
||||
.required("condition", SyntaxType::Block)
|
||||
.filter()
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, skip_while)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_while(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Where requires a condition",
|
||||
"needs condition",
|
||||
args.call_info.name_span,
|
||||
));
|
||||
}
|
||||
|
||||
let block = args.nth(0).unwrap().as_block()?;
|
||||
let input = args.input;
|
||||
|
||||
pub fn skip_while(
|
||||
SkipWhileArgs { condition }: SkipWhileArgs,
|
||||
RunnableContext { input, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let objects = input.values.skip_while(move |item| {
|
||||
let result = block.invoke(&item);
|
||||
let result = condition.invoke(&item);
|
||||
|
||||
let return_value = match result {
|
||||
Ok(v) if v.is_true() => true,
|
||||
|
|
|
@ -1,11 +1,20 @@
|
|||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let fields: Result<Vec<_>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
pub fn sort_by(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let (input, args) = args.parts();
|
||||
|
||||
let fields: Result<Vec<_>, _> = args
|
||||
.positional
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| a.as_string())
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
|
||||
let output = args.input.values.collect::<Vec<_>>();
|
||||
let output = input.values.collect::<Vec<_>>();
|
||||
|
||||
let output = output.map(move |mut vec| {
|
||||
vec.sort_by_key(|item| {
|
||||
|
|
|
@ -3,20 +3,24 @@ use crate::object::{Primitive, TaggedDictBuilder, Value};
|
|||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
|
||||
pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let positional: Vec<_> = args.positional_iter().cloned().collect();
|
||||
let span = args.call_info.name_span;
|
||||
pub fn split_column(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
let positional: Vec<_> = args.positional.iter().flatten().cloned().collect();
|
||||
|
||||
if positional.len() == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Split-column needs more information",
|
||||
"needs parameter (eg split-column \",\")",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
|
|
|
@ -3,20 +3,25 @@ use crate::object::{Primitive, Value};
|
|||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
|
||||
pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let positional: Vec<Tagged<Value>> = args.positional_iter().cloned().collect();
|
||||
let span = args.call_info.name_span;
|
||||
pub fn split_row(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let len = args.len();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
if positional.len() == 0 {
|
||||
let positional: Vec<Tagged<Value>> = args.positional.iter().flatten().cloned().collect();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Split-row needs more information",
|
||||
"needs parameter (eg split-row \"\\n\")",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let input = args.input;
|
||||
|
||||
let stream = input
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
|
|
|
@ -1,16 +1,41 @@
|
|||
use crate::commands::command::SinkCommandArgs;
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::format::TableView;
|
||||
use crate::prelude::*;
|
||||
use futures_async_stream::async_stream_block;
|
||||
|
||||
pub fn table(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
if args.input.len() > 0 {
|
||||
let mut host = args.ctx.host.lock().unwrap();
|
||||
let view = TableView::from_list(&args.input);
|
||||
if let Some(view) = view {
|
||||
handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
}
|
||||
pub struct Table;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct TableArgs {}
|
||||
|
||||
impl StaticCommand for Table {
|
||||
fn name(&self) -> &str {
|
||||
"table"
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, table)?.run()
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("table")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn table(_args: TableArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let stream = async_stream_block! {
|
||||
let input: Vec<Tagged<Value>> = context.input.into_vec().await;
|
||||
if input.len() > 0 {
|
||||
let mut host = context.host.lock().unwrap();
|
||||
let view = TableView::from_list(&input);
|
||||
if let Some(view) = view {
|
||||
handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(OutputStream::new(stream))
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
|||
use crate::object::{TaggedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn tags(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn tags(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let source_map = args.call_info.source_map.clone();
|
||||
Ok(args
|
||||
.input
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_array(
|
||||
args: CommandArgs,
|
||||
_registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input.values.collect();
|
||||
|
||||
Ok(out
|
||||
|
|
|
@ -36,9 +36,11 @@ pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match to_string(&value_to_csv_value(&a.item)) {
|
||||
|
|
|
@ -41,9 +41,11 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(
|
||||
|
|
|
@ -33,9 +33,10 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
|
|
|
@ -39,9 +39,10 @@ pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
Ok(out
|
||||
.values
|
||||
.map(
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
|||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn trim(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
|
|
|
@ -1,16 +1,41 @@
|
|||
use crate::commands::command::SinkCommandArgs;
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::format::VTableView;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn vtable(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
if args.input.len() > 0 {
|
||||
let mut host = args.ctx.host.lock().unwrap();
|
||||
let view = VTableView::from_list(&args.input);
|
||||
if let Some(view) = view {
|
||||
handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
}
|
||||
}
|
||||
pub struct VTable;
|
||||
|
||||
Ok(())
|
||||
#[derive(Deserialize)]
|
||||
pub struct VTableArgs {}
|
||||
|
||||
impl StaticCommand for VTable {
|
||||
fn name(&self) -> &str {
|
||||
"vtable"
|
||||
}
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, vtable)?.run()
|
||||
}
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("vtable")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vtable(_args: VTableArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
|
||||
let stream = async_stream_block! {
|
||||
let input = context.input.into_vec().await;
|
||||
|
||||
if input.len() > 0 {
|
||||
let mut host = context.host.lock().unwrap();
|
||||
let view = VTableView::from_list(&input);
|
||||
if let Some(view) = view {
|
||||
handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(OutputStream::new(stream))
|
||||
}
|
||||
|
|
|
@ -1,14 +1,46 @@
|
|||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Block;
|
||||
use crate::object::base as value;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry;
|
||||
use crate::prelude::*;
|
||||
|
||||
use futures::future::ready;
|
||||
use log::trace;
|
||||
use serde::Deserialize;
|
||||
|
||||
command! {
|
||||
Where as where(args, condition: Block,) {
|
||||
let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = args.input);
|
||||
pub struct Where;
|
||||
|
||||
input.values.filter_map(move |item| {
|
||||
#[derive(Deserialize)]
|
||||
struct WhereArgs {
|
||||
condition: value::Block,
|
||||
}
|
||||
|
||||
impl StaticCommand for Where {
|
||||
fn name(&self) -> &str {
|
||||
"where"
|
||||
}
|
||||
|
||||
fn signature(&self) -> registry::Signature {
|
||||
Signature::build("where").required("condition", SyntaxType::Block)
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, run)?.run()
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
WhereArgs { condition }: WhereArgs,
|
||||
context: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
Ok(context
|
||||
.input
|
||||
.values
|
||||
.filter_map(move |item| {
|
||||
let result = condition.invoke(&item);
|
||||
|
||||
let return_value = match result {
|
||||
|
@ -17,7 +49,8 @@ command! {
|
|||
_ => None,
|
||||
};
|
||||
|
||||
ready(return_value)
|
||||
ready(return_value)
|
||||
})
|
||||
}
|
||||
.boxed()
|
||||
.to_output_stream())
|
||||
}
|
||||
|
|
154
src/context.rs
154
src/context.rs
|
@ -1,18 +1,20 @@
|
|||
use crate::commands::command::{CallInfo, Sink, SinkCommandArgs};
|
||||
use crate::parser::registry::{Args, CommandConfig, CommandRegistry};
|
||||
use crate::commands::{Command, UnevaluatedCallInfo};
|
||||
use crate::parser::hir;
|
||||
use crate::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum SpanSource {
|
||||
Url(String),
|
||||
File(String),
|
||||
Source(Text),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
@ -32,35 +34,67 @@ impl SourceMap {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, new)]
|
||||
pub struct CommandRegistry {
|
||||
#[new(value = "Arc::new(Mutex::new(IndexMap::default()))")]
|
||||
registry: Arc<Mutex<IndexMap<String, Arc<Command>>>>,
|
||||
}
|
||||
|
||||
impl CommandRegistry {
|
||||
crate fn empty() -> CommandRegistry {
|
||||
CommandRegistry {
|
||||
registry: Arc::new(Mutex::new(IndexMap::default())),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn get_command(&self, name: &str) -> Option<Arc<Command>> {
|
||||
let registry = self.registry.lock().unwrap();
|
||||
|
||||
registry.get(name).map(|c| c.clone())
|
||||
}
|
||||
|
||||
fn has(&self, name: &str) -> bool {
|
||||
let registry = self.registry.lock().unwrap();
|
||||
|
||||
registry.contains_key(name)
|
||||
}
|
||||
|
||||
fn insert(&mut self, name: impl Into<String>, command: Arc<Command>) {
|
||||
let mut registry = self.registry.lock().unwrap();
|
||||
registry.insert(name.into(), command);
|
||||
}
|
||||
|
||||
// crate fn names(&self) -> Vec<String> {
|
||||
// let registry = self.registry.lock().unwrap();
|
||||
// registry.keys().cloned().collect()
|
||||
// }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
commands: IndexMap<String, Arc<dyn Command>>,
|
||||
sinks: IndexMap<String, Arc<dyn Sink>>,
|
||||
registry: CommandRegistry,
|
||||
crate source_map: SourceMap,
|
||||
crate host: Arc<Mutex<dyn Host + Send>>,
|
||||
crate shell_manager: ShellManager,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
crate fn registry(&self) -> &CommandRegistry {
|
||||
&self.registry
|
||||
}
|
||||
|
||||
crate fn basic() -> Result<Context, Box<dyn Error>> {
|
||||
Ok(Context {
|
||||
commands: indexmap::IndexMap::new(),
|
||||
sinks: indexmap::IndexMap::new(),
|
||||
registry: CommandRegistry::new(),
|
||||
source_map: SourceMap::new(),
|
||||
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
|
||||
shell_manager: ShellManager::basic()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_commands(&mut self, commands: Vec<Arc<dyn Command>>) {
|
||||
pub fn add_commands(&mut self, commands: Vec<Arc<Command>>) {
|
||||
for command in commands {
|
||||
self.commands.insert(command.name().to_string(), command);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sinks(&mut self, sinks: Vec<Arc<dyn Sink>>) {
|
||||
for sink in sinks {
|
||||
self.sinks.insert(sink.name().to_string(), sink);
|
||||
self.registry.insert(command.name().to_string(), command);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,67 +102,59 @@ impl Context {
|
|||
self.source_map.insert(uuid, span_source);
|
||||
}
|
||||
|
||||
crate fn has_sink(&self, name: &str) -> bool {
|
||||
self.sinks.contains_key(name)
|
||||
}
|
||||
|
||||
crate fn get_sink(&self, name: &str) -> Arc<dyn Sink> {
|
||||
self.sinks.get(name).unwrap().clone()
|
||||
}
|
||||
|
||||
crate fn run_sink(
|
||||
&mut self,
|
||||
command: Arc<dyn Sink>,
|
||||
name_span: Span,
|
||||
args: Args,
|
||||
input: Vec<Tagged<Value>>,
|
||||
) -> Result<(), ShellError> {
|
||||
let command_args = SinkCommandArgs {
|
||||
ctx: self.clone(),
|
||||
call_info: CallInfo {
|
||||
name_span,
|
||||
source_map: self.source_map.clone(),
|
||||
args,
|
||||
},
|
||||
input,
|
||||
};
|
||||
|
||||
command.run(command_args)
|
||||
}
|
||||
// pub fn clone_commands(&self) -> CommandRegistry {
|
||||
// self.registry.clone()
|
||||
// }
|
||||
|
||||
crate fn has_command(&self, name: &str) -> bool {
|
||||
self.commands.contains_key(name)
|
||||
self.registry.has(name)
|
||||
}
|
||||
|
||||
crate fn get_command(&self, name: &str) -> Arc<dyn Command> {
|
||||
self.commands.get(name).unwrap().clone()
|
||||
crate fn get_command(&self, name: &str) -> Arc<Command> {
|
||||
self.registry.get_command(name).unwrap()
|
||||
}
|
||||
|
||||
crate fn run_command(
|
||||
crate async fn run_command(
|
||||
&mut self,
|
||||
command: Arc<dyn Command>,
|
||||
command: Arc<Command>,
|
||||
name_span: Span,
|
||||
source_map: SourceMap,
|
||||
args: Args,
|
||||
args: hir::Call,
|
||||
source: Text,
|
||||
input: InputStream,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let command_args = CommandArgs {
|
||||
let command_args = self.command_args(args, input, source, source_map, name_span);
|
||||
command.run(command_args, self.registry()).await
|
||||
}
|
||||
|
||||
fn call_info(
|
||||
&self,
|
||||
args: hir::Call,
|
||||
source: Text,
|
||||
source_map: SourceMap,
|
||||
name_span: Span,
|
||||
) -> UnevaluatedCallInfo {
|
||||
UnevaluatedCallInfo {
|
||||
args,
|
||||
source,
|
||||
source_map,
|
||||
name_span,
|
||||
}
|
||||
}
|
||||
|
||||
fn command_args(
|
||||
&self,
|
||||
args: hir::Call,
|
||||
input: InputStream,
|
||||
source: Text,
|
||||
source_map: SourceMap,
|
||||
name_span: Span,
|
||||
) -> CommandArgs {
|
||||
CommandArgs {
|
||||
host: self.host.clone(),
|
||||
shell_manager: self.shell_manager.clone(),
|
||||
call_info: CallInfo {
|
||||
name_span,
|
||||
source_map,
|
||||
args,
|
||||
},
|
||||
call_info: self.call_info(args, source, source_map, name_span),
|
||||
input,
|
||||
};
|
||||
|
||||
command.run(command_args)
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandRegistry for Context {
|
||||
fn get(&self, name: &str) -> Option<CommandConfig> {
|
||||
self.commands.get(name).map(|c| c.config())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
src/env/host.rs
vendored
2
src/env/host.rs
vendored
|
@ -2,7 +2,7 @@ use crate::prelude::*;
|
|||
use language_reporting::termcolor;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait Host: Debug {
|
||||
pub trait Host: Debug + Send {
|
||||
fn out_terminal(&self) -> Box<term::StdoutTerminal>;
|
||||
fn err_terminal(&self) -> Box<term::StderrTerminal>;
|
||||
|
||||
|
|
|
@ -56,6 +56,15 @@ pub struct ShellError {
|
|||
cause: Option<Box<ProximateShellError>>,
|
||||
}
|
||||
|
||||
impl serde::de::Error for ShellError {
|
||||
fn custom<T>(msg: T) -> Self
|
||||
where
|
||||
T: std::fmt::Display,
|
||||
{
|
||||
ShellError::string(msg.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl ShellError {
|
||||
crate fn type_error(
|
||||
expected: impl Into<String>,
|
||||
|
|
|
@ -9,7 +9,7 @@ use derive_new::new;
|
|||
use indexmap::IndexMap;
|
||||
|
||||
#[derive(new)]
|
||||
crate struct Scope {
|
||||
pub struct Scope {
|
||||
it: Tagged<Value>,
|
||||
#[new(default)]
|
||||
vars: IndexMap<String, Tagged<Value>>,
|
||||
|
@ -22,16 +22,24 @@ impl Scope {
|
|||
vars: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn it_value(value: Tagged<Value>) -> Scope {
|
||||
Scope {
|
||||
it: value,
|
||||
vars: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn evaluate_baseline_expr(
|
||||
expr: &Expression,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Tagged<Value>, ShellError> {
|
||||
match &expr.item {
|
||||
RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)),
|
||||
RawExpression::Synthetic(hir::Synthetic::String(s)) => Ok(Value::string(s).tagged_unknown()),
|
||||
RawExpression::Variable(var) => evaluate_reference(var, scope, source),
|
||||
RawExpression::Binary(binary) => {
|
||||
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
||||
|
@ -48,6 +56,16 @@ crate fn evaluate_baseline_expr(
|
|||
)),
|
||||
}
|
||||
}
|
||||
RawExpression::List(list) => {
|
||||
let mut exprs = vec![];
|
||||
|
||||
for expr in list {
|
||||
let expr = evaluate_baseline_expr(expr, registry, scope, source)?;
|
||||
exprs.push(expr);
|
||||
}
|
||||
|
||||
Ok(Value::List(exprs).tagged(Tag::unknown_origin(expr.span())))
|
||||
}
|
||||
RawExpression::Block(block) => Ok(Tagged::from_simple_spanned_item(
|
||||
Value::Block(Block::new(block.clone(), source.clone(), expr.span())),
|
||||
expr.span(),
|
||||
|
|
|
@ -7,6 +7,7 @@ crate mod vtable;
|
|||
use crate::prelude::*;
|
||||
|
||||
crate use entries::EntriesView;
|
||||
#[allow(unused)]
|
||||
crate use generic::GenericView;
|
||||
crate use table::TableView;
|
||||
crate use vtable::VTableView;
|
||||
|
|
|
@ -7,7 +7,7 @@ use prettytable::format::{FormatBuilder, LinePosition, LineSeparator};
|
|||
|
||||
use prettytable::{color, Attr, Cell, Row, Table};
|
||||
|
||||
#[derive(new)]
|
||||
#[derive(Debug, new)]
|
||||
pub struct TableView {
|
||||
headers: Vec<String>,
|
||||
entries: Vec<Vec<String>>,
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(async_await)]
|
||||
#![feature(generators)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(bind_by_move_pattern_guards)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(type_ascription)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(option_flattening)]
|
||||
#![feature(specialization)]
|
||||
#![feature(proc_macro_hygiene)]
|
||||
|
||||
#[macro_use]
|
||||
mod prelude;
|
||||
|
@ -23,16 +27,19 @@ mod parser;
|
|||
mod plugin;
|
||||
mod shell;
|
||||
mod stream;
|
||||
mod traits;
|
||||
mod utils;
|
||||
|
||||
pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue};
|
||||
pub use crate::context::{SourceMap, SpanSource};
|
||||
pub use crate::env::host::BasicHost;
|
||||
pub use crate::object::base::OF64;
|
||||
pub use crate::plugin::{serve_plugin, Plugin};
|
||||
pub use crate::utils::{AbsolutePath, RelativePath};
|
||||
pub use cli::cli;
|
||||
pub use errors::ShellError;
|
||||
pub use object::base::{Primitive, Value};
|
||||
pub use object::dict::{Dictionary, TaggedDictBuilder};
|
||||
pub use object::meta::{Span, Tag, Tagged, TaggedItem};
|
||||
pub use parser::parse::text::Text;
|
||||
pub use parser::registry::{Args, CommandConfig, NamedType, PositionalType};
|
||||
pub use parser::registry::{EvaluatedArgs, NamedType, PositionalType, Signature};
|
||||
|
|
|
@ -7,6 +7,7 @@ crate mod meta;
|
|||
crate mod process;
|
||||
crate mod types;
|
||||
|
||||
#[allow(unused)]
|
||||
crate use base::{Block, Primitive, Switch, Value};
|
||||
crate use dict::{Dictionary, TaggedDictBuilder};
|
||||
crate use files::dir_entry_dict;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::context::CommandRegistry;
|
||||
use crate::errors::ShellError;
|
||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||
use crate::object::TaggedDictBuilder;
|
||||
|
@ -9,7 +10,7 @@ use chrono::{DateTime, Utc};
|
|||
use chrono_humanize::Humanize;
|
||||
use derive_new::new;
|
||||
use ordered_float::OrderedFloat;
|
||||
use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
|
@ -127,42 +128,13 @@ pub struct Operation {
|
|||
crate right: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new)]
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Serialize, Deserialize, new)]
|
||||
pub struct Block {
|
||||
crate expressions: Vec<hir::Expression>,
|
||||
crate source: Text,
|
||||
crate span: Span,
|
||||
}
|
||||
|
||||
impl Serialize for Block {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut seq = serializer.serialize_seq(None)?;
|
||||
|
||||
let list = self
|
||||
.expressions
|
||||
.iter()
|
||||
.map(|e| e.source(&self.source.clone()));
|
||||
|
||||
for item in list {
|
||||
seq.serialize_element(item.as_ref())?;
|
||||
}
|
||||
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize<'de> for Block {
|
||||
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
unimplemented!("deserialize block")
|
||||
}
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn invoke(&self, value: &Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
||||
let scope = Scope::new(value.clone());
|
||||
|
@ -174,7 +146,12 @@ impl Block {
|
|||
let mut last = None;
|
||||
|
||||
for expr in self.expressions.iter() {
|
||||
last = Some(evaluate_baseline_expr(&expr, &(), &scope, &self.source)?)
|
||||
last = Some(evaluate_baseline_expr(
|
||||
&expr,
|
||||
&CommandRegistry::empty(),
|
||||
&scope,
|
||||
&self.source,
|
||||
)?)
|
||||
}
|
||||
|
||||
Ok(last.unwrap())
|
||||
|
@ -259,12 +236,14 @@ impl std::convert::TryFrom<&'a Tagged<Value>> for i64 {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum Switch {
|
||||
Present,
|
||||
Absent,
|
||||
}
|
||||
|
||||
impl Switch {
|
||||
#[allow(unused)]
|
||||
pub fn is_present(&self) -> bool {
|
||||
match self {
|
||||
Switch::Present => true,
|
||||
|
@ -507,15 +486,15 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn as_pair(&self) -> Result<(Tagged<Value>, Tagged<Value>), ShellError> {
|
||||
match self {
|
||||
Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
|
||||
other => Err(ShellError::string(format!(
|
||||
"Expected pair, got {:?}",
|
||||
other
|
||||
))),
|
||||
}
|
||||
}
|
||||
// crate fn as_pair(&self) -> Result<(Tagged<Value>, Tagged<Value>), ShellError> {
|
||||
// match self {
|
||||
// Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
|
||||
// other => Err(ShellError::string(format!(
|
||||
// "Expected pair, got {:?}",
|
||||
// other
|
||||
// ))),
|
||||
// }
|
||||
// }
|
||||
|
||||
crate fn as_string(&self) -> Result<String, ShellError> {
|
||||
match self {
|
||||
|
@ -544,17 +523,6 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn as_block(&self) -> Result<Block, ShellError> {
|
||||
match self {
|
||||
Value::Block(block) => Ok(block.clone()),
|
||||
// TODO: this should definitely be more general with better errors
|
||||
other => Err(ShellError::string(format!(
|
||||
"Expected block, got {:?}",
|
||||
other
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn is_true(&self) -> bool {
|
||||
match self {
|
||||
Value::Primitive(Primitive::Boolean(true)) => true,
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
use crate::commands::from_toml::convert_toml_value_to_nu_value;
|
||||
use crate::commands::to_toml::value_to_toml_value;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{Dictionary, Value};
|
||||
use crate::prelude::*;
|
||||
use app_dirs::*;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs::{self, OpenOptions};
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const APP_INFO: AppInfo = AppInfo {
|
||||
name: "nu",
|
||||
|
@ -19,6 +22,13 @@ struct Config {
|
|||
extra: IndexMap<String, Tagged<Value>>,
|
||||
}
|
||||
|
||||
crate fn config_path() -> Result<PathBuf, ShellError> {
|
||||
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
||||
|
||||
Ok(location.join("config.toml"))
|
||||
}
|
||||
|
||||
crate fn write_config(config: &IndexMap<String, Tagged<Value>>) -> Result<(), ShellError> {
|
||||
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
||||
|
@ -26,9 +36,9 @@ crate fn write_config(config: &IndexMap<String, Tagged<Value>>) -> Result<(), Sh
|
|||
let filename = location.join("config.toml");
|
||||
touch(&filename)?;
|
||||
|
||||
let contents = toml::to_string(&Config {
|
||||
extra: config.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
|
||||
})?;
|
||||
let contents = value_to_toml_value(&Value::Object(Dictionary::new(config.clone())));
|
||||
|
||||
let contents = toml::to_string(&contents)?;
|
||||
|
||||
fs::write(&filename, &contents)?;
|
||||
|
||||
|
@ -50,10 +60,18 @@ crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Tagged<Value>>
|
|||
.map(|v| v.simple_spanned(span))
|
||||
.map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?;
|
||||
|
||||
let parsed: Config = toml::from_str(&contents)
|
||||
let parsed: toml::Value = toml::from_str(&contents)
|
||||
.map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?;
|
||||
|
||||
Ok(parsed.extra)
|
||||
let value = convert_toml_value_to_nu_value(&parsed, Tag::unknown_origin(span));
|
||||
let tag = value.tag();
|
||||
match value.item {
|
||||
Value::Object(Dictionary { entries }) => Ok(entries),
|
||||
other => Err(ShellError::type_error(
|
||||
"Dictionary",
|
||||
other.type_name().tagged(tag),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
// A simple implementation of `% touch path` (ignores existing files)
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use crate::prelude::*;
|
||||
use crate::Text;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_derive::Deserialize;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
|
@ -11,6 +12,12 @@ pub struct Tagged<T> {
|
|||
pub item: T,
|
||||
}
|
||||
|
||||
impl<T> HasSpan for Tagged<T> {
|
||||
fn span(&self) -> Span {
|
||||
self.tag.span
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TaggedItem: Sized {
|
||||
fn tagged(self, tag: impl Into<Tag>) -> Tagged<Self> {
|
||||
Tagged::from_item(self, tag.into())
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
use crate::object::base as value;
|
||||
use crate::parser::hir;
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use serde_derive::Deserialize;
|
||||
use log::trace;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub trait Type: std::fmt::Debug + Send {
|
||||
type Extractor: ExtractType;
|
||||
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
pub trait ExtractType: Sized {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError>;
|
||||
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError>;
|
||||
|
@ -19,8 +12,120 @@ pub trait ExtractType: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> ExtractType for T {
|
||||
default fn extract(_value: &Tagged<Value>) -> Result<T, ShellError> {
|
||||
let name = std::intrinsics::type_name::<T>();
|
||||
Err(ShellError::unimplemented(format!(
|
||||
"<T> ExtractType for {}",
|
||||
name
|
||||
)))
|
||||
}
|
||||
|
||||
default fn check(_value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||
Err(ShellError::unimplemented("ExtractType for T"))
|
||||
}
|
||||
|
||||
default fn syntax_type() -> hir::SyntaxType {
|
||||
hir::SyntaxType::Any
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ExtractType> ExtractType for Vec<Tagged<T>> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError> {
|
||||
let name = std::intrinsics::type_name::<T>();
|
||||
trace!("<Vec> Extracting {:?} for Vec<{}>", value, name);
|
||||
|
||||
match value.item() {
|
||||
Value::List(items) => {
|
||||
let mut out = vec![];
|
||||
|
||||
for item in items {
|
||||
out.push(T::extract(item)?.tagged(item.tag()));
|
||||
}
|
||||
|
||||
Ok(out)
|
||||
}
|
||||
other => Err(ShellError::type_error(
|
||||
"Vec",
|
||||
other.type_name().tagged(value.tag()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||
match value.item() {
|
||||
Value::List(_) => Ok(value),
|
||||
other => Err(ShellError::type_error(
|
||||
"Vec",
|
||||
other.type_name().tagged(value.tag()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn syntax_type() -> hir::SyntaxType {
|
||||
hir::SyntaxType::List
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ExtractType, U: ExtractType> ExtractType for (T, U) {
|
||||
fn extract(value: &Tagged<Value>) -> Result<(T, U), ShellError> {
|
||||
let t_name = std::intrinsics::type_name::<T>();
|
||||
let u_name = std::intrinsics::type_name::<U>();
|
||||
|
||||
trace!("Extracting {:?} for ({}, {})", value, t_name, u_name);
|
||||
|
||||
match value.item() {
|
||||
Value::List(items) => {
|
||||
if items.len() == 2 {
|
||||
let first = &items[0];
|
||||
let second = &items[1];
|
||||
|
||||
Ok((T::extract(first)?, U::extract(second)?))
|
||||
} else {
|
||||
Err(ShellError::type_error(
|
||||
"two-element-tuple",
|
||||
"not-two".tagged(value.tag()),
|
||||
))
|
||||
}
|
||||
}
|
||||
other => Err(ShellError::type_error(
|
||||
"two-element-tuple",
|
||||
other.type_name().tagged(value.tag()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ExtractType> ExtractType for Option<T> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Option<T>, ShellError> {
|
||||
let name = std::intrinsics::type_name::<T>();
|
||||
trace!("<Option> Extracting {:?} for Option<{}>", value, name);
|
||||
|
||||
let result = match value.item() {
|
||||
Value::Primitive(Primitive::Nothing) => None,
|
||||
_ => Some(T::extract(value)?),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||
match value.item() {
|
||||
Value::Primitive(Primitive::Nothing) => Ok(value),
|
||||
_ => T::check(value),
|
||||
}
|
||||
}
|
||||
|
||||
fn syntax_type() -> hir::SyntaxType {
|
||||
T::syntax_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ExtractType> ExtractType for Tagged<T> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Tagged<T>, ShellError> {
|
||||
let name = std::intrinsics::type_name::<T>();
|
||||
trace!("<Tagged> Extracting {:?} for Tagged<{}>", value, name);
|
||||
|
||||
Ok(T::extract(value)?.tagged(value.tag()))
|
||||
}
|
||||
|
||||
|
@ -33,25 +138,52 @@ impl<T: ExtractType> ExtractType for Tagged<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct Any;
|
||||
impl ExtractType for Value {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Value, ShellError> {
|
||||
trace!("<Tagged> Extracting {:?} for Value", value);
|
||||
|
||||
impl Type for Any {
|
||||
type Extractor = Tagged<Value>;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Any"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for Tagged<Value> {
|
||||
fn extract(value: &Tagged<Value>) -> Result<Self, ShellError> {
|
||||
Ok(value.clone())
|
||||
Ok(value.item().clone())
|
||||
}
|
||||
|
||||
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn syntax_type() -> hir::SyntaxType {
|
||||
SyntaxType::Any
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for bool {
|
||||
fn syntax_type() -> hir::SyntaxType {
|
||||
hir::SyntaxType::Boolean
|
||||
}
|
||||
|
||||
fn extract(value: &'a Tagged<Value>) -> Result<bool, ShellError> {
|
||||
trace!("Extracting {:?} for bool", value);
|
||||
|
||||
match &value {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::Boolean(b)),
|
||||
..
|
||||
} => Ok(*b),
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::Nothing),
|
||||
..
|
||||
} => Ok(false),
|
||||
other => Err(ShellError::type_error("Boolean", other.tagged_type_name())),
|
||||
}
|
||||
}
|
||||
|
||||
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||
match &value {
|
||||
value @ Tagged {
|
||||
item: Value::Primitive(Primitive::Boolean(_)),
|
||||
..
|
||||
} => Ok(value),
|
||||
other => Err(ShellError::type_error("Boolean", other.tagged_type_name())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for std::path::PathBuf {
|
||||
|
@ -60,6 +192,8 @@ impl ExtractType for std::path::PathBuf {
|
|||
}
|
||||
|
||||
fn extract(value: &'a Tagged<Value>) -> Result<std::path::PathBuf, ShellError> {
|
||||
trace!("Extracting {:?} for PathBuf", value);
|
||||
|
||||
match &value {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(p)),
|
||||
|
@ -80,19 +214,10 @@ impl ExtractType for std::path::PathBuf {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct Integer;
|
||||
|
||||
impl Type for Integer {
|
||||
type Extractor = i64;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Integer"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for i64 {
|
||||
fn extract(value: &Tagged<Value>) -> Result<i64, ShellError> {
|
||||
trace!("Extracting {:?} for i64", value);
|
||||
|
||||
match value {
|
||||
&Tagged {
|
||||
item: Value::Primitive(Primitive::Int(int)),
|
||||
|
@ -113,19 +238,10 @@ impl ExtractType for i64 {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct NuString;
|
||||
|
||||
impl Type for NuString {
|
||||
type Extractor = String;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Integer"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for String {
|
||||
fn extract(value: &Tagged<Value>) -> Result<String, ShellError> {
|
||||
trace!("Extracting {:?} for String", value);
|
||||
|
||||
match value {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(string)),
|
||||
|
@ -146,19 +262,10 @@ impl ExtractType for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
|
||||
pub struct Block;
|
||||
|
||||
impl Type for Block {
|
||||
type Extractor = value::Block;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Block"
|
||||
}
|
||||
}
|
||||
|
||||
impl ExtractType for value::Block {
|
||||
fn check(value: &'value Tagged<Value>) -> Result<&'value Tagged<Value>, ShellError> {
|
||||
trace!("Extracting {:?} for Block", value);
|
||||
|
||||
match value {
|
||||
v @ Tagged {
|
||||
item: Value::Block(_),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
crate mod deserializer;
|
||||
crate mod hir;
|
||||
crate mod parse;
|
||||
crate mod parse_command;
|
||||
|
@ -5,6 +6,7 @@ crate mod registry;
|
|||
|
||||
use crate::errors::ShellError;
|
||||
|
||||
crate use deserializer::ConfigDeserializer;
|
||||
crate use hir::baseline_parse_tokens::baseline_parse_tokens;
|
||||
crate use parse::call_node::CallNode;
|
||||
crate use parse::files::Files;
|
||||
|
|
309
src/parser/deserializer.rs
Normal file
309
src/parser/deserializer.rs
Normal file
|
@ -0,0 +1,309 @@
|
|||
use crate::commands::command::EvaluatedCommandArgs;
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
use serde::{de, forward_to_deserialize_any};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeserializerItem<'de> {
|
||||
key: String,
|
||||
struct_field: &'de str,
|
||||
val: Tagged<Value>,
|
||||
}
|
||||
|
||||
pub struct ConfigDeserializer<'de> {
|
||||
args: EvaluatedCommandArgs,
|
||||
stack: Vec<DeserializerItem<'de>>,
|
||||
saw_root: bool,
|
||||
position: usize,
|
||||
}
|
||||
|
||||
impl ConfigDeserializer<'de> {
|
||||
pub fn from_call_node(args: EvaluatedCommandArgs) -> ConfigDeserializer<'de> {
|
||||
ConfigDeserializer {
|
||||
args,
|
||||
stack: vec![],
|
||||
saw_root: false,
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, name: &'static str) -> Result<(), ShellError> {
|
||||
let value: Option<Tagged<Value>> = if name == "rest" {
|
||||
let positional = self.args.slice_from(self.position);
|
||||
self.position += positional.len();
|
||||
Some(Value::List(positional).tagged_unknown()) // TODO: correct span
|
||||
} else {
|
||||
if self.args.has(name) {
|
||||
self.args.get(name).map(|x| x.clone())
|
||||
} else {
|
||||
let position = self.position;
|
||||
self.position += 1;
|
||||
self.args.nth(position).map(|x| x.clone())
|
||||
}
|
||||
};
|
||||
|
||||
trace!("pushing {:?}", value);
|
||||
|
||||
self.stack.push(DeserializerItem {
|
||||
key: name.to_string(),
|
||||
struct_field: name,
|
||||
val: value.unwrap_or_else(|| {
|
||||
Value::nothing().tagged(Tag::unknown_origin(self.args.call_info.name_span))
|
||||
}),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> DeserializerItem {
|
||||
let value = self.stack.pop();
|
||||
trace!("popping value :: {:?}", value);
|
||||
value.expect("Can't pop an empty stack")
|
||||
}
|
||||
}
|
||||
|
||||
use de::Visitor;
|
||||
|
||||
impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
|
||||
type Error = ShellError;
|
||||
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
let value = self.pop();
|
||||
let name = std::intrinsics::type_name::<V::Value>();
|
||||
trace!("<Deserialize any> Extracting {:?}", name);
|
||||
|
||||
V::Value::extract(&value.val)
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! { bool option seq }
|
||||
|
||||
fn deserialize_i8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i8")
|
||||
}
|
||||
fn deserialize_i16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i16")
|
||||
}
|
||||
fn deserialize_i32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i32")
|
||||
}
|
||||
fn deserialize_i64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_i64")
|
||||
}
|
||||
fn deserialize_u8<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u8")
|
||||
}
|
||||
fn deserialize_u16<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u16")
|
||||
}
|
||||
fn deserialize_u32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u32")
|
||||
}
|
||||
fn deserialize_u64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_u64")
|
||||
}
|
||||
fn deserialize_f32<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_f32")
|
||||
}
|
||||
fn deserialize_f64<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_f64")
|
||||
}
|
||||
fn deserialize_char<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_char")
|
||||
}
|
||||
fn deserialize_str<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_str")
|
||||
}
|
||||
fn deserialize_string<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_string")
|
||||
}
|
||||
fn deserialize_bytes<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_bytes")
|
||||
}
|
||||
fn deserialize_byte_buf<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_byte_buf")
|
||||
}
|
||||
|
||||
fn deserialize_unit<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_unit")
|
||||
}
|
||||
fn deserialize_unit_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_unit_struct")
|
||||
}
|
||||
fn deserialize_newtype_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_newtype_struct")
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_tuple")
|
||||
}
|
||||
fn deserialize_tuple_struct<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_tuple_struct")
|
||||
}
|
||||
fn deserialize_map<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_map")
|
||||
}
|
||||
fn deserialize_struct<V>(
|
||||
mut self,
|
||||
name: &'static str,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
trace!(
|
||||
"deserializing struct {:?} {:?} (stack={:?})",
|
||||
name,
|
||||
fields,
|
||||
self.stack
|
||||
);
|
||||
|
||||
if self.saw_root {
|
||||
let value = self.pop();
|
||||
let name = std::intrinsics::type_name::<V::Value>();
|
||||
trace!("Extracting {:?} for {:?}", value.val, name);
|
||||
V::Value::extract(&value.val)
|
||||
} else {
|
||||
self.saw_root = true;
|
||||
visitor.visit_seq(StructDeserializer::new(&mut self, fields))
|
||||
}
|
||||
}
|
||||
fn deserialize_enum<V>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
_visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_enum")
|
||||
}
|
||||
fn deserialize_identifier<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_identifier")
|
||||
}
|
||||
fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
unimplemented!("deserialize_ignored_any")
|
||||
}
|
||||
}
|
||||
|
||||
struct StructDeserializer<'a, 'de: 'a> {
|
||||
de: &'a mut ConfigDeserializer<'de>,
|
||||
fields: &'static [&'static str],
|
||||
}
|
||||
|
||||
impl<'a, 'de: 'a> StructDeserializer<'a, 'de> {
|
||||
fn new(de: &'a mut ConfigDeserializer<'de>, fields: &'static [&'static str]) -> Self {
|
||||
StructDeserializer {
|
||||
de: de,
|
||||
fields: fields,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'de: 'a> de::SeqAccess<'de> for StructDeserializer<'a, 'de> {
|
||||
type Error = ShellError;
|
||||
|
||||
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
|
||||
where
|
||||
T: de::DeserializeSeed<'de>,
|
||||
{
|
||||
if self.fields.len() == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
trace!("Processing {}", self.fields[0]);
|
||||
|
||||
self.de.push(self.fields[0])?;
|
||||
self.fields = &self.fields[1..];
|
||||
seed.deserialize(&mut *self.de).map(Some)
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
return Some(self.fields.len());
|
||||
}
|
||||
}
|
|
@ -4,11 +4,13 @@ crate mod binary;
|
|||
crate mod named;
|
||||
crate mod path;
|
||||
|
||||
use crate::parser::Unit;
|
||||
use crate::Span;
|
||||
use crate::Tagged;
|
||||
use crate::evaluate::Scope;
|
||||
use crate::parser::{registry, Unit};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
crate use baseline_parse::{baseline_parse_single_token, baseline_parse_token_as_string};
|
||||
crate use baseline_parse_tokens::{baseline_parse_next_expr, SyntaxType, TokensIterator};
|
||||
|
@ -25,7 +27,7 @@ pub fn path(head: impl Into<Expression>, tail: Vec<Tagged<impl Into<String>>>) -
|
|||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Getters, new)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Getters, Serialize, Deserialize, new)]
|
||||
pub struct Call {
|
||||
#[get = "crate"]
|
||||
head: Box<Expression>,
|
||||
|
@ -35,23 +37,72 @@ pub struct Call {
|
|||
named: Option<NamedArguments>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
impl Call {
|
||||
pub fn evaluate(
|
||||
&self,
|
||||
registry: ®istry::CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<registry::EvaluatedArgs, ShellError> {
|
||||
registry::evaluate_args(self, registry, scope, source)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToDebug for Call {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
write!(f, "({}", self.head.debug(source))?;
|
||||
|
||||
if let Some(positional) = &self.positional {
|
||||
write!(f, " ")?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
&itertools::join(positional.iter().map(|p| p.debug(source)), " ")
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(named) = &self.named {
|
||||
write!(f, "{}", named.debug(source))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum RawExpression {
|
||||
Literal(Literal),
|
||||
Synthetic(Synthetic),
|
||||
Variable(Variable),
|
||||
Binary(Box<Binary>),
|
||||
Block(Vec<Expression>),
|
||||
List(Vec<Expression>),
|
||||
Path(Box<Path>),
|
||||
|
||||
#[allow(unused)]
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum Synthetic {
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl Synthetic {
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
match self {
|
||||
Synthetic::String(_) => "string",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawExpression {
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
match self {
|
||||
RawExpression::Literal(literal) => literal.type_name(),
|
||||
RawExpression::Synthetic(synthetic) => synthetic.type_name(),
|
||||
RawExpression::Variable(..) => "variable",
|
||||
RawExpression::List(..) => "list",
|
||||
RawExpression::Binary(..) => "binary",
|
||||
RawExpression::Block(..) => "block",
|
||||
RawExpression::Path(..) => "path",
|
||||
|
@ -63,36 +114,40 @@ impl RawExpression {
|
|||
pub type Expression = Tagged<RawExpression>;
|
||||
|
||||
impl Expression {
|
||||
fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
|
||||
crate fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
|
||||
Tagged::from_simple_spanned_item(RawExpression::Literal(Literal::Integer(i.into())), span)
|
||||
}
|
||||
|
||||
fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
|
||||
crate fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
|
||||
Tagged::from_simple_spanned_item(
|
||||
RawExpression::Literal(Literal::Size(i.into(), unit.into())),
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
crate fn synthetic_string(s: impl Into<String>) -> Expression {
|
||||
RawExpression::Synthetic(Synthetic::String(s.into())).tagged_unknown()
|
||||
}
|
||||
|
||||
crate fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
Tagged::from_simple_spanned_item(
|
||||
RawExpression::Literal(Literal::String(inner.into())),
|
||||
outer.into(),
|
||||
)
|
||||
}
|
||||
|
||||
fn bare(span: impl Into<Span>) -> Expression {
|
||||
crate fn bare(span: impl Into<Span>) -> Expression {
|
||||
Tagged::from_simple_spanned_item(RawExpression::Literal(Literal::Bare), span.into())
|
||||
}
|
||||
|
||||
fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
crate fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
Tagged::from_simple_spanned_item(
|
||||
RawExpression::Variable(Variable::Other(inner.into())),
|
||||
outer.into(),
|
||||
)
|
||||
}
|
||||
|
||||
fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
crate fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
Tagged::from_simple_spanned_item(
|
||||
RawExpression::Variable(Variable::It(inner.into())),
|
||||
outer.into(),
|
||||
|
@ -100,13 +155,46 @@ impl Expression {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToDebug for Expression {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
match self.item() {
|
||||
RawExpression::Literal(l) => write!(f, "{:?}", l),
|
||||
RawExpression::Synthetic(Synthetic::String(s)) => write!(f, "{:?}", s),
|
||||
RawExpression::Variable(Variable::It(_)) => write!(f, "$it"),
|
||||
RawExpression::Variable(Variable::Other(s)) => write!(f, "${}", s.slice(source)),
|
||||
RawExpression::Binary(b) => write!(f, "{}", b.debug(source)),
|
||||
RawExpression::Block(exprs) => {
|
||||
write!(f, "{{ ")?;
|
||||
|
||||
for expr in exprs {
|
||||
write!(f, "{} ", expr.debug(source))?;
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
RawExpression::List(exprs) => {
|
||||
write!(f, "[ ")?;
|
||||
|
||||
for expr in exprs {
|
||||
write!(f, "{} ", expr.debug(source))?;
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
}
|
||||
RawExpression::Path(p) => write!(f, "{}", p.debug(source)),
|
||||
RawExpression::Boolean(true) => write!(f, "$yes"),
|
||||
RawExpression::Boolean(false) => write!(f, "$no"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Tagged<Path>> for Expression {
|
||||
fn from(path: Tagged<Path>) -> Expression {
|
||||
path.map(|p| RawExpression::Path(Box::new(p)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum Literal {
|
||||
Integer(i64),
|
||||
Size(i64, Unit),
|
||||
|
@ -114,6 +202,17 @@ pub enum Literal {
|
|||
Bare,
|
||||
}
|
||||
|
||||
impl ToDebug for Tagged<&Literal> {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
match self.item() {
|
||||
Literal::Integer(int) => write!(f, "{}", *int),
|
||||
Literal::Size(int, unit) => write!(f, "{}{:?}", *int, unit),
|
||||
Literal::String(span) => write!(f, "{}", span.slice(source)),
|
||||
Literal::Bare => write!(f, "{}", self.span().slice(source)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
fn type_name(&self) -> &'static str {
|
||||
match self {
|
||||
|
@ -125,7 +224,7 @@ impl Literal {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum Variable {
|
||||
It(Span),
|
||||
Other(Span),
|
||||
|
|
|
@ -8,11 +8,11 @@ use crate::parser::{
|
|||
use crate::{Span, Tag, Tagged, TaggedItem, Text};
|
||||
use derive_new::new;
|
||||
use log::trace;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn baseline_parse_tokens(
|
||||
token_nodes: &mut TokensIterator<'_>,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<Vec<hir::Expression>, ShellError> {
|
||||
let mut exprs: Vec<hir::Expression> = vec![];
|
||||
|
@ -33,6 +33,7 @@ pub fn baseline_parse_tokens(
|
|||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum SyntaxType {
|
||||
Any,
|
||||
List,
|
||||
Literal,
|
||||
Variable,
|
||||
Path,
|
||||
|
@ -43,7 +44,7 @@ pub enum SyntaxType {
|
|||
|
||||
pub fn baseline_parse_next_expr(
|
||||
tokens: &mut TokensIterator,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
syntax_type: SyntaxType,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
|
@ -175,7 +176,7 @@ pub fn baseline_parse_next_expr(
|
|||
|
||||
pub fn baseline_parse_semantic_token(
|
||||
token: &TokenNode,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
match token {
|
||||
|
@ -196,7 +197,7 @@ pub fn baseline_parse_semantic_token(
|
|||
|
||||
pub fn baseline_parse_delimited(
|
||||
token: &Tagged<DelimitedNode>,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
match token.delimiter() {
|
||||
|
@ -209,13 +210,20 @@ pub fn baseline_parse_delimited(
|
|||
Ok(Tagged::from_simple_spanned_item(expr, token.span()))
|
||||
}
|
||||
Delimiter::Paren => unimplemented!(),
|
||||
Delimiter::Square => unimplemented!(),
|
||||
Delimiter::Square => {
|
||||
let children = token.children();
|
||||
let exprs =
|
||||
baseline_parse_tokens(&mut TokensIterator::new(children), registry, source)?;
|
||||
|
||||
let expr = hir::RawExpression::List(exprs);
|
||||
Ok(expr.tagged(Tag::unknown_origin(token.span())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn baseline_parse_path(
|
||||
token: &Tagged<PathNode>,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
let head = baseline_parse_semantic_token(token.head(), registry, source)?;
|
||||
|
|
|
@ -1,12 +1,27 @@
|
|||
use crate::parser::{hir::Expression, Operator};
|
||||
use crate::prelude::*;
|
||||
use crate::Tagged;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, new)]
|
||||
#[derive(
|
||||
Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new,
|
||||
)]
|
||||
#[get = "crate"]
|
||||
pub struct Binary {
|
||||
left: Expression,
|
||||
op: Tagged<Operator>,
|
||||
right: Expression,
|
||||
}
|
||||
|
||||
impl ToDebug for Binary {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
write!(f, "{}", self.left.debug(source))?;
|
||||
write!(f, " {} ", self.op.debug(source))?;
|
||||
write!(f, "{}", self.right.debug(source))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
use crate::parser::hir::Expression;
|
||||
use crate::parser::Flag;
|
||||
use crate::prelude::*;
|
||||
use crate::Span;
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum NamedValue {
|
||||
AbsentSwitch,
|
||||
PresentSwitch(Span),
|
||||
|
@ -13,12 +16,27 @@ pub enum NamedValue {
|
|||
Value(Expression),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, new)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, new)]
|
||||
pub struct NamedArguments {
|
||||
#[new(default)]
|
||||
crate named: IndexMap<String, NamedValue>,
|
||||
}
|
||||
|
||||
impl ToDebug for NamedArguments {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
for (name, value) in &self.named {
|
||||
match value {
|
||||
NamedValue::AbsentSwitch => continue,
|
||||
NamedValue::PresentSwitch(span) => write!(f, " {}", span.slice(source))?,
|
||||
NamedValue::AbsentValue => continue,
|
||||
NamedValue::Value(expr) => write!(f, " --{} {}", name, expr.debug(source))?,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedArguments {
|
||||
pub fn insert_switch(&mut self, name: impl Into<String>, switch: Option<Flag>) {
|
||||
let name = name.into();
|
||||
|
|
|
@ -1,11 +1,28 @@
|
|||
use crate::parser::hir::Expression;
|
||||
use crate::prelude::*;
|
||||
use crate::Tagged;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, new)]
|
||||
#[derive(
|
||||
Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new,
|
||||
)]
|
||||
#[get = "crate"]
|
||||
pub struct Path {
|
||||
head: Expression,
|
||||
tail: Vec<Tagged<String>>,
|
||||
}
|
||||
|
||||
impl ToDebug for Path {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
write!(f, "{}", self.head.debug(source))?;
|
||||
|
||||
for part in &self.tail {
|
||||
write!(f, ".{}", part.item())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::Span;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
|
||||
pub enum FlagKind {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use serde_derive::{Deserialize, Serialize};
|
||||
use crate::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
|
||||
|
@ -11,6 +13,12 @@ pub enum Operator {
|
|||
GreaterThanOrEqual,
|
||||
}
|
||||
|
||||
impl ToDebug for Operator {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, _source: &str) -> fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
#[allow(unused)]
|
||||
pub fn print(&self) -> String {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
|
@ -202,3 +203,21 @@ where
|
|||
self.partial_cmp(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Text {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.as_ref().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize<'de> for Text {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(Text::from(String::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
use crate::object::base::Value;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
|
||||
pub enum Unit {
|
||||
|
@ -46,7 +46,7 @@ impl FromStr for Unit {
|
|||
type Err = ();
|
||||
fn from_str(input: &str) -> Result<Self, <Self as std::str::FromStr>::Err> {
|
||||
match input {
|
||||
"B" | "b" => Ok(Unit::B),
|
||||
"B" | "b" => Ok(Unit::B),
|
||||
"KB" | "kb" | "Kb" | "K" | "k" => Ok(Unit::KB),
|
||||
"MB" | "mb" | "Mb" => Ok(Unit::MB),
|
||||
"GB" | "gb" | "Gb" => Ok(Unit::GB),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::errors::{ArgumentError, ShellError};
|
||||
use crate::parser::registry::{CommandConfig, CommandRegistry, NamedType, PositionalType};
|
||||
use crate::parser::registry::{CommandRegistry, NamedType, PositionalType, Signature};
|
||||
use crate::parser::{baseline_parse_tokens, CallNode};
|
||||
use crate::parser::{
|
||||
hir::{self, NamedArguments},
|
||||
|
@ -9,8 +9,8 @@ use crate::{Span, Tag, Tagged, Text};
|
|||
use log::trace;
|
||||
|
||||
pub fn parse_command(
|
||||
config: &CommandConfig,
|
||||
registry: &dyn CommandRegistry,
|
||||
config: &Signature,
|
||||
registry: &CommandRegistry,
|
||||
call: &Tagged<CallNode>,
|
||||
source: &Text,
|
||||
) -> Result<hir::Call, ShellError> {
|
||||
|
@ -62,8 +62,8 @@ fn parse_command_head(head: &TokenNode) -> Result<hir::Expression, ShellError> {
|
|||
}
|
||||
|
||||
fn parse_command_tail(
|
||||
config: &CommandConfig,
|
||||
registry: &dyn CommandRegistry,
|
||||
config: &Signature,
|
||||
registry: &CommandRegistry,
|
||||
tail: Option<Vec<TokenNode>>,
|
||||
source: &Text,
|
||||
command_span: Span,
|
||||
|
@ -77,7 +77,7 @@ fn parse_command_tail(
|
|||
|
||||
trace_remaining("nodes", tail.clone(), source);
|
||||
|
||||
for (name, kind) in config.named() {
|
||||
for (name, kind) in &config.named {
|
||||
trace!(target: "nu::parse", "looking for {} : {:?}", name, kind);
|
||||
|
||||
match kind {
|
||||
|
@ -115,7 +115,7 @@ fn parse_command_tail(
|
|||
|
||||
if tail.at_end() {
|
||||
return Err(ShellError::argument_error(
|
||||
config.name().clone(),
|
||||
config.name.clone(),
|
||||
ArgumentError::MissingValueForName(name.to_string()),
|
||||
flag.span(),
|
||||
));
|
||||
|
@ -139,14 +139,14 @@ fn parse_command_tail(
|
|||
|
||||
let mut positional = vec![];
|
||||
|
||||
for arg in config.positional() {
|
||||
for arg in &config.positional {
|
||||
trace!("Processing positional {:?}", arg);
|
||||
|
||||
match arg {
|
||||
PositionalType::Mandatory(..) => {
|
||||
if tail.len() == 0 {
|
||||
return Err(ShellError::argument_error(
|
||||
config.name().clone(),
|
||||
config.name.clone(),
|
||||
ArgumentError::MissingMandatoryPositional(arg.name().to_string()),
|
||||
command_span,
|
||||
));
|
||||
|
@ -197,7 +197,7 @@ fn extract_switch(name: &str, tokens: &mut hir::TokensIterator<'_>, source: &Tex
|
|||
}
|
||||
|
||||
fn extract_mandatory(
|
||||
config: &CommandConfig,
|
||||
config: &Signature,
|
||||
name: &str,
|
||||
tokens: &mut hir::TokensIterator<'a>,
|
||||
source: &Text,
|
||||
|
@ -207,7 +207,7 @@ fn extract_mandatory(
|
|||
|
||||
match flag {
|
||||
None => Err(ShellError::argument_error(
|
||||
config.name().clone(),
|
||||
config.name.clone(),
|
||||
ArgumentError::MissingMandatoryFlag(name.to_string()),
|
||||
span,
|
||||
)),
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
// TODO: Temporary redirect
|
||||
crate use crate::context::CommandRegistry;
|
||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||
use crate::parser::{hir, hir::SyntaxType, parse_command, CallNode};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -68,29 +69,85 @@ impl PositionalType {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Getters, Serialize, Deserialize, Clone)]
|
||||
#[get = "crate"]
|
||||
pub struct CommandConfig {
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, new)]
|
||||
pub struct Signature {
|
||||
pub name: String,
|
||||
#[new(default)]
|
||||
pub positional: Vec<PositionalType>,
|
||||
#[new(value = "false")]
|
||||
pub rest_positional: bool,
|
||||
#[new(default)]
|
||||
pub named: IndexMap<String, NamedType>,
|
||||
#[new(value = "false")]
|
||||
pub is_filter: bool,
|
||||
pub is_sink: bool,
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
pub fn build(name: impl Into<String>) -> Signature {
|
||||
Signature::new(name.into())
|
||||
}
|
||||
|
||||
pub fn required(mut self, name: impl Into<String>, ty: impl Into<SyntaxType>) -> Signature {
|
||||
self.positional
|
||||
.push(PositionalType::Mandatory(name.into(), ty.into()));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn optional(mut self, name: impl Into<String>, ty: impl Into<SyntaxType>) -> Signature {
|
||||
self.positional
|
||||
.push(PositionalType::Optional(name.into(), ty.into()));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn named(mut self, name: impl Into<String>, ty: impl Into<SyntaxType>) -> Signature {
|
||||
self.named
|
||||
.insert(name.into(), NamedType::Optional(ty.into()));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn required_named(
|
||||
mut self,
|
||||
name: impl Into<String>,
|
||||
ty: impl Into<SyntaxType>,
|
||||
) -> Signature {
|
||||
self.named
|
||||
.insert(name.into(), NamedType::Mandatory(ty.into()));
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn switch(mut self, name: impl Into<String>) -> Signature {
|
||||
self.named.insert(name.into(), NamedType::Switch);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn filter(mut self) -> Signature {
|
||||
self.is_filter = true;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn rest(mut self) -> Signature {
|
||||
self.rest_positional = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, new, Serialize, Deserialize, Clone)]
|
||||
pub struct Args {
|
||||
pub struct EvaluatedArgs {
|
||||
pub positional: Option<Vec<Tagged<Value>>>,
|
||||
pub named: Option<IndexMap<String, Tagged<Value>>>,
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct DebugPositional<'a> {
|
||||
pub struct DebugEvaluatedPositional<'a> {
|
||||
positional: &'a Option<Vec<Tagged<Value>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugPositional<'a> {
|
||||
impl fmt::Debug for DebugEvaluatedPositional<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.positional {
|
||||
None => write!(f, "None"),
|
||||
|
@ -103,11 +160,11 @@ impl fmt::Debug for DebugPositional<'a> {
|
|||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct DebugNamed<'a> {
|
||||
pub struct DebugEvaluatedNamed<'a> {
|
||||
named: &'a Option<IndexMap<String, Tagged<Value>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugNamed<'a> {
|
||||
impl fmt::Debug for DebugEvaluatedNamed<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.named {
|
||||
None => write!(f, "None"),
|
||||
|
@ -119,24 +176,27 @@ impl fmt::Debug for DebugNamed<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct DebugArgs<'a> {
|
||||
args: &'a Args,
|
||||
pub struct DebugEvaluatedArgs<'a> {
|
||||
args: &'a EvaluatedArgs,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugArgs<'a> {
|
||||
impl fmt::Debug for DebugEvaluatedArgs<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut s = f.debug_struct("Args");
|
||||
|
||||
s.field("positional", &DebugPositional::new(&self.args.positional));
|
||||
s.field("named", &DebugNamed::new(&self.args.named));
|
||||
s.field(
|
||||
"positional",
|
||||
&DebugEvaluatedPositional::new(&self.args.positional),
|
||||
);
|
||||
s.field("named", &DebugEvaluatedNamed::new(&self.args.named));
|
||||
|
||||
s.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn debug(&'a self) -> DebugArgs<'a> {
|
||||
DebugArgs { args: self }
|
||||
impl EvaluatedArgs {
|
||||
pub fn debug(&'a self) -> DebugEvaluatedArgs<'a> {
|
||||
DebugEvaluatedArgs { args: self }
|
||||
}
|
||||
|
||||
pub fn nth(&self, pos: usize) -> Option<&Tagged<Value>> {
|
||||
|
@ -204,19 +264,18 @@ impl Iterator for PositionalIter<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl CommandConfig {
|
||||
crate fn evaluate_args(
|
||||
impl Signature {
|
||||
crate fn parse_args(
|
||||
&self,
|
||||
call: &Tagged<CallNode>,
|
||||
registry: &dyn CommandRegistry,
|
||||
scope: &Scope,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<Args, ShellError> {
|
||||
) -> Result<hir::Call, ShellError> {
|
||||
let args = parse_command(self, registry, call, source)?;
|
||||
|
||||
trace!("parsed args: {:?}", args);
|
||||
|
||||
evaluate_args(args, registry, scope, source)
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
@ -225,25 +284,25 @@ impl CommandConfig {
|
|||
}
|
||||
}
|
||||
|
||||
fn evaluate_args(
|
||||
args: hir::Call,
|
||||
registry: &dyn CommandRegistry,
|
||||
crate fn evaluate_args(
|
||||
call: &hir::Call,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Args, ShellError> {
|
||||
let positional: Result<Option<Vec<_>>, _> = args
|
||||
) -> Result<EvaluatedArgs, ShellError> {
|
||||
let positional: Result<Option<Vec<_>>, _> = call
|
||||
.positional()
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
p.iter()
|
||||
.map(|e| evaluate_baseline_expr(e, &(), scope, source))
|
||||
.map(|e| evaluate_baseline_expr(e, &CommandRegistry::empty(), scope, source))
|
||||
.collect()
|
||||
})
|
||||
.transpose();
|
||||
|
||||
let positional = positional?;
|
||||
|
||||
let named: Result<Option<IndexMap<String, Tagged<Value>>>, ShellError> = args
|
||||
let named: Result<Option<IndexMap<String, Tagged<Value>>>, ShellError> = call
|
||||
.named()
|
||||
.as_ref()
|
||||
.map(|n| {
|
||||
|
@ -274,15 +333,5 @@ fn evaluate_args(
|
|||
|
||||
let named = named?;
|
||||
|
||||
Ok(Args::new(positional, named))
|
||||
}
|
||||
|
||||
pub trait CommandRegistry {
|
||||
fn get(&self, name: &str) -> Option<CommandConfig>;
|
||||
}
|
||||
|
||||
impl CommandRegistry for () {
|
||||
fn get(&self, _name: &str) -> Option<CommandConfig> {
|
||||
None
|
||||
}
|
||||
Ok(EvaluatedArgs::new(positional, named))
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::Signature;
|
||||
use crate::Tagged;
|
||||
use crate::{CallInfo, CommandConfig, ReturnValue, ShellError, Value};
|
||||
use crate::{CallInfo, ReturnValue, ShellError, Value};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io;
|
||||
|
||||
pub trait Plugin {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError>;
|
||||
fn config(&mut self) -> Result<Signature, ShellError>;
|
||||
|
||||
#[allow(unused)]
|
||||
fn begin_filter(&mut self, call_info: CallInfo) -> Result<Vec<ReturnValue>, ShellError> {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||
ReturnValue, ShellError, Tagged, Value,
|
||||
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
||||
ShellError, Signature, Tagged, Value,
|
||||
};
|
||||
|
||||
struct Add {
|
||||
|
@ -41,15 +41,14 @@ impl Add {
|
|||
}
|
||||
|
||||
impl Plugin for Add {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "add".to_string(),
|
||||
positional: vec![
|
||||
PositionalType::mandatory_any("Field"),
|
||||
PositionalType::mandatory_any("Value"),
|
||||
],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use crossterm::{cursor, terminal, Attribute, RawScreen};
|
||||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, NamedType, Plugin, ShellError, SpanSource, Tagged, Value,
|
||||
serve_plugin, CallInfo, NamedType, Plugin, ShellError, Signature, SpanSource, Tagged, Value,
|
||||
};
|
||||
use pretty_hex::*;
|
||||
|
||||
|
@ -15,14 +15,13 @@ impl BinaryView {
|
|||
}
|
||||
|
||||
impl Plugin for BinaryView {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
let mut named = IndexMap::new();
|
||||
named.insert("lores".to_string(), NamedType::Switch);
|
||||
Ok(CommandConfig {
|
||||
Ok(Signature {
|
||||
name: "binaryview".to_string(),
|
||||
positional: vec![],
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
named,
|
||||
rest_positional: false,
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||
ReturnValue, ShellError, Tagged, Value,
|
||||
serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue,
|
||||
ShellError, Signature, Tagged, Value,
|
||||
};
|
||||
|
||||
struct Edit {
|
||||
|
@ -41,15 +41,14 @@ impl Edit {
|
|||
}
|
||||
|
||||
impl Plugin for Edit {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "edit".to_string(),
|
||||
positional: vec![
|
||||
PositionalType::mandatory_any("Field"),
|
||||
PositionalType::mandatory_any("Value"),
|
||||
],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, NamedType, Plugin, PositionalType, Primitive,
|
||||
ReturnSuccess, ReturnValue, ShellError, Tagged, TaggedItem, Value,
|
||||
serve_plugin, CallInfo, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||
ReturnValue, ShellError, Signature, Tagged, TaggedItem, Value,
|
||||
};
|
||||
|
||||
struct Inc {
|
||||
|
@ -84,17 +84,16 @@ impl Inc {
|
|||
}
|
||||
|
||||
impl Plugin for Inc {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
let mut named = IndexMap::new();
|
||||
named.insert("major".to_string(), NamedType::Switch);
|
||||
named.insert("minor".to_string(), NamedType::Switch);
|
||||
named.insert("patch".to_string(), NamedType::Switch);
|
||||
|
||||
Ok(CommandConfig {
|
||||
Ok(Signature {
|
||||
name: "inc".to_string(),
|
||||
positional: vec![PositionalType::optional_any("Field")],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named,
|
||||
rest_positional: true,
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, Plugin, Primitive, ReturnSuccess, ReturnValue,
|
||||
ShellError, Tagged, Value,
|
||||
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
||||
Tagged, Value,
|
||||
};
|
||||
|
||||
struct Skip {
|
||||
|
@ -14,12 +14,11 @@ impl Skip {
|
|||
}
|
||||
|
||||
impl Plugin for Skip {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "skip".to_string(),
|
||||
positional: vec![],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, NamedType, Plugin, PositionalType, Primitive,
|
||||
ReturnSuccess, ReturnValue, ShellError, Tagged, Value,
|
||||
serve_plugin, CallInfo, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess,
|
||||
ReturnValue, ShellError, Signature, Tagged, Value,
|
||||
};
|
||||
|
||||
enum Action {
|
||||
|
@ -121,17 +121,16 @@ impl Str {
|
|||
}
|
||||
|
||||
impl Plugin for Str {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
let mut named = IndexMap::new();
|
||||
named.insert("downcase".to_string(), NamedType::Switch);
|
||||
named.insert("upcase".to_string(), NamedType::Switch);
|
||||
named.insert("to-int".to_string(), NamedType::Switch);
|
||||
|
||||
Ok(CommandConfig {
|
||||
Ok(Signature {
|
||||
name: "str".to_string(),
|
||||
positional: vec![PositionalType::optional_any("Field")],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named,
|
||||
rest_positional: true,
|
||||
})
|
||||
|
@ -194,8 +193,8 @@ mod tests {
|
|||
use super::Str;
|
||||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
Args, CallInfo, Plugin, ReturnSuccess, SourceMap, Span, Tag, Tagged, TaggedDictBuilder,
|
||||
TaggedItem, Value,
|
||||
CallInfo, EvaluatedArgs, Plugin, ReturnSuccess, SourceMap, Span, Tag, Tagged,
|
||||
TaggedDictBuilder, TaggedItem, Value,
|
||||
};
|
||||
|
||||
struct CallStub {
|
||||
|
@ -227,7 +226,7 @@ mod tests {
|
|||
|
||||
fn create(&self, name_span: Span) -> CallInfo {
|
||||
CallInfo {
|
||||
args: Args::new(Some(self.positionals.clone()), Some(self.flags.clone())),
|
||||
args: EvaluatedArgs::new(Some(self.positionals.clone()), Some(self.flags.clone())),
|
||||
source_map: SourceMap::new(),
|
||||
name_span,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, Plugin, Primitive, ReturnSuccess, ReturnValue,
|
||||
ShellError, Tag, Tagged, Value,
|
||||
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
||||
Tag, Tagged, Value,
|
||||
};
|
||||
|
||||
struct Sum {
|
||||
|
@ -63,12 +63,11 @@ impl Sum {
|
|||
}
|
||||
|
||||
impl Plugin for Sum {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "sum".to_string(),
|
||||
positional: vec![],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
|
|
|
@ -5,8 +5,8 @@ use futures::stream::StreamExt;
|
|||
use heim::{disk, memory};
|
||||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, Plugin, Primitive, ReturnSuccess, ReturnValue,
|
||||
ShellError, Tag, Tagged, TaggedDictBuilder, Value, OF64,
|
||||
serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature,
|
||||
Tag, Tagged, TaggedDictBuilder, Value, OF64,
|
||||
};
|
||||
use std::ffi::OsStr;
|
||||
|
||||
|
@ -175,12 +175,11 @@ async fn sysinfo(tag: Tag) -> Vec<Tagged<Value>> {
|
|||
}
|
||||
|
||||
impl Plugin for Sys {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "sys".to_string(),
|
||||
positional: vec![],
|
||||
is_filter: true,
|
||||
is_sink: false,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use crossterm::{cursor, terminal, RawScreen};
|
||||
use indexmap::IndexMap;
|
||||
use nu::{
|
||||
serve_plugin, CallInfo, CommandConfig, Plugin, Primitive, ShellError, SourceMap, SpanSource,
|
||||
serve_plugin, CallInfo, Plugin, Primitive, ShellError, Signature, SourceMap, SpanSource,
|
||||
Tagged, Value,
|
||||
};
|
||||
use rawkey::RawKey;
|
||||
|
@ -29,12 +29,11 @@ impl TextView {
|
|||
}
|
||||
|
||||
impl Plugin for TextView {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "textview".to_string(),
|
||||
positional: vec![],
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: false,
|
||||
})
|
||||
|
@ -239,6 +238,8 @@ fn view_text_value(value: &Tagged<Value>, source_map: &SourceMap) {
|
|||
None
|
||||
}
|
||||
}
|
||||
//FIXME: this probably isn't correct
|
||||
SpanSource::Source(_source) => None,
|
||||
};
|
||||
|
||||
match extension {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use nu::{serve_plugin, CallInfo, CommandConfig, Plugin, ShellError, Tagged, Value};
|
||||
use nu::{serve_plugin, CallInfo, Plugin, ShellError, Signature, Tagged, Value};
|
||||
use ptree::item::StringItem;
|
||||
use ptree::output::print_tree_with;
|
||||
use ptree::print_config::PrintConfig;
|
||||
|
@ -80,12 +80,11 @@ impl TreeView {
|
|||
struct TreeViewer;
|
||||
|
||||
impl Plugin for TreeViewer {
|
||||
fn config(&mut self) -> Result<CommandConfig, ShellError> {
|
||||
Ok(CommandConfig {
|
||||
fn config(&mut self) -> Result<Signature, ShellError> {
|
||||
Ok(Signature {
|
||||
name: "tree".to_string(),
|
||||
positional: vec![],
|
||||
is_filter: false,
|
||||
is_sink: true,
|
||||
named: IndexMap::new(),
|
||||
rest_positional: true,
|
||||
})
|
||||
|
|
|
@ -34,24 +34,32 @@ macro_rules! trace_stream {
|
|||
|
||||
crate use crate::cli::MaybeOwned;
|
||||
crate use crate::commands::command::{
|
||||
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, Sink, SinkCommandArgs,
|
||||
CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext,
|
||||
};
|
||||
crate use crate::commands::StaticCommand;
|
||||
crate use crate::context::CommandRegistry;
|
||||
crate use crate::context::{Context, SpanSource};
|
||||
crate use crate::env::host::handle_unexpected;
|
||||
crate use crate::env::Host;
|
||||
crate use crate::errors::ShellError;
|
||||
crate use crate::object::base as value;
|
||||
crate use crate::object::meta::{Tag, Tagged, TaggedItem};
|
||||
crate use crate::object::types::ExtractType;
|
||||
crate use crate::object::{Primitive, Value};
|
||||
crate use crate::parser::hir::SyntaxType;
|
||||
crate use crate::parser::registry::Signature;
|
||||
crate use crate::shell::filesystem_shell::FilesystemShell;
|
||||
crate use crate::shell::shell_manager::ShellManager;
|
||||
crate use crate::shell::value_shell::ValueShell;
|
||||
crate use crate::stream::{InputStream, OutputStream};
|
||||
crate use crate::traits::{HasSpan, ToDebug};
|
||||
crate use crate::Span;
|
||||
crate use crate::Text;
|
||||
crate use futures::stream::BoxStream;
|
||||
crate use futures::Stream;
|
||||
crate use futures::{FutureExt, StreamExt};
|
||||
crate use futures::{FutureExt, Stream, StreamExt};
|
||||
crate use futures_async_stream::async_stream_block;
|
||||
#[allow(unused)]
|
||||
crate use serde::{Deserialize, Serialize};
|
||||
crate use std::collections::VecDeque;
|
||||
crate use std::future::Future;
|
||||
crate use std::sync::{Arc, Mutex};
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use derive_new::new;
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::completion::{self, FilenameCompleter};
|
||||
use rustyline::line_buffer::LineBuffer;
|
||||
use rustyline::completion::{Completer, FilenameCompleter};
|
||||
|
||||
#[derive(new)]
|
||||
crate struct NuCompleter {
|
||||
|
@ -9,15 +7,13 @@ crate struct NuCompleter {
|
|||
//pub commands: indexmap::IndexMap<String, Arc<dyn Command>>,
|
||||
}
|
||||
|
||||
impl Completer for NuCompleter {
|
||||
type Candidate = completion::Pair;
|
||||
|
||||
fn complete(
|
||||
impl NuCompleter {
|
||||
pub fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
context: &rustyline::Context,
|
||||
) -> rustyline::Result<(usize, Vec<completion::Pair>)> {
|
||||
) -> rustyline::Result<(usize, Vec<rustyline::completion::Pair>)> {
|
||||
//let commands: Vec<String> = self.commands.keys().cloned().collect();
|
||||
|
||||
let mut completions = self.file_completer.complete(line, pos, context)?.1;
|
||||
|
@ -67,7 +63,7 @@ impl Completer for NuCompleter {
|
|||
}
|
||||
|
||||
if matched {
|
||||
completions.push(completion::Pair {
|
||||
completions.push(CompletionPair {
|
||||
display: command.clone(),
|
||||
replacement: command.clone(),
|
||||
});
|
||||
|
@ -78,8 +74,8 @@ impl Completer for NuCompleter {
|
|||
Ok((replace_pos, completions))
|
||||
}
|
||||
|
||||
fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
|
||||
let end = line.pos();
|
||||
line.replace(start..end, elected)
|
||||
}
|
||||
// fn update(&self, line: &mut LineBuffer, start: usize, elected: &str) {
|
||||
// let end = line.pos();
|
||||
// line.replace(start..end, elected)
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::commands::command::CallInfo;
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::object::dir_entry_dict;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::completer::NuCompleter;
|
||||
use crate::shell::shell::Shell;
|
||||
use rustyline::completion::{self, Completer, FilenameCompleter};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::completion::FilenameCompleter;
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
use std::path::{Path, PathBuf};
|
||||
pub struct FilesystemShell {
|
||||
|
@ -54,10 +53,10 @@ impl Shell for FilesystemShell {
|
|||
"filesystem".to_string()
|
||||
}
|
||||
|
||||
fn ls(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
fn ls(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let cwd = self.path.clone();
|
||||
let mut full_path = PathBuf::from(&self.path);
|
||||
match &call_info.args.nth(0) {
|
||||
match &args.nth(0) {
|
||||
Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)),
|
||||
_ => {}
|
||||
}
|
||||
|
@ -78,7 +77,7 @@ impl Shell for FilesystemShell {
|
|||
|
||||
let entries = match entries {
|
||||
Err(e) => {
|
||||
if let Some(s) = call_info.args.nth(0) {
|
||||
if let Some(s) = args.nth(0) {
|
||||
return Err(ShellError::labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
|
@ -88,7 +87,7 @@ impl Shell for FilesystemShell {
|
|||
return Err(ShellError::labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
call_info.name_span,
|
||||
args.name_span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +100,7 @@ impl Shell for FilesystemShell {
|
|||
let value = dir_entry_dict(
|
||||
filename,
|
||||
&entry.metadata()?,
|
||||
Tag::unknown_origin(call_info.name_span),
|
||||
Tag::unknown_origin(args.call_info.name_span),
|
||||
)?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
|
@ -118,7 +117,7 @@ impl Shell for FilesystemShell {
|
|||
let value = dir_entry_dict(
|
||||
filename,
|
||||
&metadata,
|
||||
Tag::unknown_origin(call_info.name_span),
|
||||
Tag::unknown_origin(args.call_info.name_span),
|
||||
)?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
|
@ -127,15 +126,15 @@ impl Shell for FilesystemShell {
|
|||
Ok(shell_entries.to_output_stream())
|
||||
}
|
||||
|
||||
fn cd(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
let path = match call_info.args.nth(0) {
|
||||
fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let path = match args.nth(0) {
|
||||
None => match dirs::home_dir() {
|
||||
Some(o) => o,
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to home directory",
|
||||
"can not go to home",
|
||||
call_info.name_span,
|
||||
args.call_info.name_span,
|
||||
))
|
||||
}
|
||||
},
|
||||
|
@ -159,11 +158,11 @@ impl Shell for FilesystemShell {
|
|||
match std::env::set_current_dir(&path) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
if call_info.args.len() > 0 {
|
||||
if args.len() > 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Can not change to directory",
|
||||
"directory not found",
|
||||
call_info.args.nth(0).unwrap().span().clone(),
|
||||
args.nth(0).unwrap().span().clone(),
|
||||
));
|
||||
} else {
|
||||
return Err(ShellError::string("Can not change to directory"));
|
||||
|
@ -194,22 +193,16 @@ impl Shell for FilesystemShell {
|
|||
};
|
||||
self.path = path.to_string_lossy().to_string();
|
||||
}
|
||||
}
|
||||
|
||||
impl Completer for FilesystemShell {
|
||||
type Candidate = completion::Pair;
|
||||
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
||||
self.completer.complete(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Hinter for FilesystemShell {
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
self.hinter.hint(line, pos, ctx)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::parser::{Pipeline, PipelineElement};
|
|||
use crate::shell::shell_manager::ShellManager;
|
||||
use crate::Tagged;
|
||||
use ansi_term::Color;
|
||||
use rustyline::completion::{self, Completer};
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::highlight::Highlighter;
|
||||
use rustyline::hint::Hinter;
|
||||
|
@ -22,17 +22,33 @@ impl Helper {
|
|||
}
|
||||
|
||||
impl Completer for Helper {
|
||||
type Candidate = completion::Pair;
|
||||
type Candidate = rustyline::completion::Pair;
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||
self.helper.complete(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl Completer for Helper {
|
||||
type Candidate = rustyline::completion::Pair;
|
||||
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
|
||||
self.helper.complete(line, pos, ctx)
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), ReadlineError> {
|
||||
let result = self.helper.complete(line, pos, ctx);
|
||||
|
||||
result.map(|(x, y)| (x, y.iter().map(|z| z.into()).collect()))
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl Hinter for Helper {
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
use crate::commands::command::CallInfo;
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::errors::ShellError;
|
||||
use crate::stream::{InputStream, OutputStream};
|
||||
use rustyline::{completion::Completer, hint::Hinter};
|
||||
use crate::stream::OutputStream;
|
||||
|
||||
pub trait Shell
|
||||
where
|
||||
Self: Completer<Candidate = rustyline::completion::Pair>,
|
||||
Self: Hinter,
|
||||
{
|
||||
pub trait Shell {
|
||||
fn name(&self) -> String;
|
||||
fn ls(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError>;
|
||||
fn cd(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError>;
|
||||
fn ls(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError>;
|
||||
fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError>;
|
||||
fn path(&self) -> String;
|
||||
fn set_path(&mut self, path: String);
|
||||
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError>;
|
||||
|
||||
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String>;
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
use crate::commands::command::CallInfo;
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::errors::ShellError;
|
||||
use crate::shell::filesystem_shell::FilesystemShell;
|
||||
use crate::shell::shell::Shell;
|
||||
use crate::stream::{InputStream, OutputStream};
|
||||
use rustyline::completion::{self, Completer};
|
||||
use rustyline::error::ReadlineError;
|
||||
use crate::stream::OutputStream;
|
||||
use std::error::Error;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ShellManager {
|
||||
crate shells: Arc<Mutex<Vec<Box<dyn Shell>>>>,
|
||||
crate shells: Arc<Mutex<Vec<Box<dyn Shell + Send>>>>,
|
||||
}
|
||||
|
||||
impl ShellManager {
|
||||
|
@ -20,7 +18,7 @@ impl ShellManager {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn push(&mut self, shell: Box<dyn Shell>) {
|
||||
pub fn push(&mut self, shell: Box<dyn Shell + Send>) {
|
||||
self.shells.lock().unwrap().push(shell);
|
||||
self.set_path(self.path());
|
||||
}
|
||||
|
@ -51,7 +49,7 @@ impl ShellManager {
|
|||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
||||
self.shells
|
||||
.lock()
|
||||
.unwrap()
|
||||
|
@ -87,14 +85,14 @@ impl ShellManager {
|
|||
self.set_path(self.path());
|
||||
}
|
||||
|
||||
pub fn ls(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
pub fn ls(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env.last().unwrap().ls(call_info, input)
|
||||
env.last().unwrap().ls(args)
|
||||
}
|
||||
pub fn cd(&self, call_info: CallInfo, input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
pub fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env.last().unwrap().cd(call_info, input)
|
||||
env.last().unwrap().cd(args)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use crate::commands::command::CallInfo;
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::shell::Shell;
|
||||
use rustyline::completion::{self, Completer};
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::hint::Hinter;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -60,15 +57,15 @@ impl Shell for ValueShell {
|
|||
"value".to_string()
|
||||
}
|
||||
|
||||
fn ls(&self, _call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
fn ls(&self, _args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(self
|
||||
.members()
|
||||
.map(|x| ReturnSuccess::value(x))
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn cd(&self, call_info: CallInfo, _input: InputStream) -> Result<OutputStream, ShellError> {
|
||||
let path = match call_info.args.nth(0) {
|
||||
fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let path = match args.nth(0) {
|
||||
None => "/".to_string(),
|
||||
Some(v) => {
|
||||
let target = v.as_string()?;
|
||||
|
@ -102,17 +99,13 @@ impl Shell for ValueShell {
|
|||
let _ = std::env::set_current_dir(&path);
|
||||
self.path = path.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl Completer for ValueShell {
|
||||
type Candidate = completion::Pair;
|
||||
|
||||
fn complete(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
_ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<completion::Pair>), ReadlineError> {
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
||||
let mut completions = vec![];
|
||||
|
||||
let mut possible_completion = vec![];
|
||||
|
@ -153,7 +146,7 @@ impl Completer for ValueShell {
|
|||
}
|
||||
|
||||
if matched {
|
||||
completions.push(completion::Pair {
|
||||
completions.push(rustyline::completion::Pair {
|
||||
display: command.to_string(),
|
||||
replacement: command.to_string(),
|
||||
});
|
||||
|
@ -161,9 +154,7 @@ impl Completer for ValueShell {
|
|||
}
|
||||
Ok((replace_pos, completions))
|
||||
}
|
||||
}
|
||||
|
||||
impl Hinter for ValueShell {
|
||||
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -9,6 +9,13 @@ impl InputStream {
|
|||
self.values.collect()
|
||||
}
|
||||
|
||||
pub fn drain_vec(&mut self) -> impl Future<Output = Vec<Tagged<Value>>> {
|
||||
let mut values: BoxStream<'static, Tagged<Value>> = VecDeque::new().boxed();
|
||||
std::mem::swap(&mut values, &mut self.values);
|
||||
|
||||
values.collect()
|
||||
}
|
||||
|
||||
pub fn from_stream(input: impl Stream<Item = Tagged<Value>> + Send + 'static) -> InputStream {
|
||||
InputStream {
|
||||
values: input.boxed(),
|
||||
|
@ -46,12 +53,23 @@ pub struct OutputStream {
|
|||
}
|
||||
|
||||
impl OutputStream {
|
||||
#[allow(unused)]
|
||||
pub fn new(values: impl Stream<Item = ReturnValue> + Send + 'static) -> OutputStream {
|
||||
OutputStream {
|
||||
values: values.boxed(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> OutputStream {
|
||||
let v: VecDeque<ReturnValue> = VecDeque::new();
|
||||
v.into()
|
||||
}
|
||||
|
||||
pub fn one(item: impl Into<ReturnValue>) -> OutputStream {
|
||||
let mut v: VecDeque<ReturnValue> = VecDeque::new();
|
||||
v.push_back(item.into());
|
||||
v.into()
|
||||
}
|
||||
|
||||
pub fn from_input(input: impl Stream<Item = Tagged<Value>> + Send + 'static) -> OutputStream {
|
||||
OutputStream {
|
||||
values: input.map(ReturnSuccess::value).boxed(),
|
||||
|
@ -59,6 +77,17 @@ impl OutputStream {
|
|||
}
|
||||
}
|
||||
|
||||
impl Stream for OutputStream {
|
||||
type Item = ReturnValue;
|
||||
|
||||
fn poll_next(
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> core::task::Poll<Option<Self::Item>> {
|
||||
Stream::poll_next(std::pin::Pin::new(&mut self.values), cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InputStream> for OutputStream {
|
||||
fn from(input: InputStream) -> OutputStream {
|
||||
OutputStream {
|
||||
|
|
28
src/traits.rs
Normal file
28
src/traits.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use crate::prelude::*;
|
||||
use std::fmt;
|
||||
|
||||
pub struct Debuggable<'a, T: ToDebug> {
|
||||
inner: &'a T,
|
||||
source: &'a str,
|
||||
}
|
||||
|
||||
impl<T: ToDebug> fmt::Display for Debuggable<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.inner.fmt_debug(f, self.source)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasSpan {
|
||||
fn span(&self) -> Span;
|
||||
}
|
||||
|
||||
pub trait ToDebug: Sized {
|
||||
fn debug(&'a self, source: &'a str) -> Debuggable<'a, Self> {
|
||||
Debuggable {
|
||||
inner: self,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result;
|
||||
}
|
72
src/utils.rs
Normal file
72
src/utils.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use std::ops::Div;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct AbsolutePath {
|
||||
inner: PathBuf,
|
||||
}
|
||||
|
||||
impl AbsolutePath {
|
||||
pub fn new(path: impl AsRef<Path>) -> AbsolutePath {
|
||||
let path = path.as_ref();
|
||||
|
||||
if path.is_absolute() {
|
||||
AbsolutePath {
|
||||
inner: path.to_path_buf(),
|
||||
}
|
||||
} else {
|
||||
panic!("AbsolutePath::new must take an absolute path")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<&str> for &AbsolutePath {
|
||||
type Output = AbsolutePath;
|
||||
|
||||
fn div(self, rhs: &str) -> Self::Output {
|
||||
let parts = rhs.split("/");
|
||||
let mut result = self.inner.clone();
|
||||
|
||||
for part in parts {
|
||||
result = result.join(part);
|
||||
}
|
||||
|
||||
AbsolutePath::new(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Path> for AbsolutePath {
|
||||
fn as_ref(&self) -> &Path {
|
||||
self.inner.as_path()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RelativePath {
|
||||
inner: PathBuf,
|
||||
}
|
||||
|
||||
impl RelativePath {
|
||||
pub fn new(path: impl Into<PathBuf>) -> RelativePath {
|
||||
let path = path.into();
|
||||
|
||||
if path.is_relative() {
|
||||
RelativePath { inner: path }
|
||||
} else {
|
||||
panic!("RelativePath::new must take a relative path")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str>> Div<T> for &RelativePath {
|
||||
type Output = RelativePath;
|
||||
|
||||
fn div(self, rhs: T) -> Self::Output {
|
||||
let parts = rhs.as_ref().split("/");
|
||||
let mut result = self.inner.clone();
|
||||
|
||||
for part in parts {
|
||||
result = result.join(part);
|
||||
}
|
||||
|
||||
RelativePath::new(result)
|
||||
}
|
||||
}
|
|
@ -203,10 +203,14 @@ fn rm_removes_files_with_wildcard() {
|
|||
"rm \"src/*/*/*.rs\""
|
||||
);
|
||||
|
||||
assert!(!h::files_exist_at(vec![
|
||||
Path::new("src/parser/parse/token_tree.rs"),
|
||||
Path::new("src/parser/hir/baseline_parse.rs"),
|
||||
Path::new("src/parser/hir/baseline_parse_tokens.rs")], PathBuf::from(&full_path)));
|
||||
assert!(!h::files_exist_at(
|
||||
vec![
|
||||
Path::new("src/parser/parse/token_tree.rs"),
|
||||
Path::new("src/parser/hir/baseline_parse.rs"),
|
||||
Path::new("src/parser/hir/baseline_parse_tokens.rs")
|
||||
],
|
||||
PathBuf::from(&full_path)
|
||||
));
|
||||
|
||||
assert_eq!(
|
||||
Playground::glob_vec(&format!("{}/src/*/*/*.rs", &full_path)),
|
||||
|
@ -230,11 +234,7 @@ fn rm_removes_directory_contents_with_recursive_flag() {
|
|||
"rm rm_test_recursive --recursive"
|
||||
);
|
||||
|
||||
let expected = format!(
|
||||
"{}/{}",
|
||||
Playground::root(),
|
||||
sandbox
|
||||
);
|
||||
let expected = format!("{}/{}", Playground::root(), sandbox);
|
||||
|
||||
assert!(!h::file_exists_at(PathBuf::from(expected)));
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue