Merge pull request #265 from jonathandturner/defer-evaluation

Defer evaluation - part 1
This commit is contained in:
Jonathan Turner 2019-08-10 10:40:10 +12:00 committed by GitHub
commit a38ae910ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
102 changed files with 2765 additions and 1163 deletions

View file

@ -1,5 +1,5 @@
variables:
lkg-rust-nightly: "2019-07-04"
lkg-rust-nightly: "2019-08-08"
trigger:
- master

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
/target
**/*.rs.bk
history.txt
tests/fixtures/nuplayground

71
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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,
}))
}
}
}

View file

@ -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;

View file

@ -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 {

View file

@ -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)
}

View file

@ -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;

View file

@ -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()
}

View file

@ -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: &registry::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: &registry::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) -> &registry::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: &registry::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: &registry::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: &registry::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(&registry, &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, &registry::CommandRegistry) -> Result<OutputStream, ShellError>
+ Send
+ Sync,
>,
}
impl StaticCommand for FnRawCommand {
fn name(&self) -> &str {
&self.name
}
fn run(
&self,
args: CommandArgs,
registry: &registry::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, &registry::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,
})
})))
}

View file

@ -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: &registry::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());
}

View file

@ -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)

View file

@ -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;

View file

@ -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(

View file

@ -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 {

View file

@ -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),
))
}

View file

@ -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

View file

@ -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| {

View file

@ -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| {

View file

@ -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| {

View file

@ -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| {

View file

@ -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| {

View file

@ -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),
..

View file

@ -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

View file

@ -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)
}

View file

@ -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![],

View file

@ -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) {

View file

@ -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())
}

View file

@ -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: &registry::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(

View file

@ -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

View file

@ -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))
}

View file

@ -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())
}

View file

@ -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();

View file

@ -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());

View file

@ -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");

View file

@ -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))
}
}

View file

@ -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;

View file

@ -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

View file

@ -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,

View file

@ -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| {

View file

@ -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 {

View file

@ -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 {

View file

@ -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))
}

View file

@ -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

View file

@ -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

View file

@ -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)) {

View file

@ -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(

View file

@ -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

View file

@ -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(

View file

@ -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

View file

@ -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))
}

View file

@ -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: &registry::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())
}

View file

@ -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
View file

@ -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>;

View file

@ -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>,

View file

@ -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(),

View file

@ -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;

View file

@ -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>>,

View file

@ -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};

View file

@ -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;

View file

@ -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,

View file

@ -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)

View file

@ -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())

View file

@ -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(_),

View file

@ -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
View 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());
}
}

View file

@ -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: &registry::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),

View file

@ -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)?;

View file

@ -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(())
}
}

View file

@ -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();

View file

@ -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(())
}
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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)?))
}
}

View file

@ -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),

View file

@ -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,
)),

View file

@ -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))
}

View file

@ -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> {

View file

@ -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,
})

View file

@ -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,
})

View file

@ -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,
})

View file

@ -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,
})

View file

@ -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,
})

View file

@ -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,
}

View file

@ -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,
})

View file

@ -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,
})

View file

@ -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 {

View file

@ -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,
})

View file

@ -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};

View file

@ -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)
// }
}

View file

@ -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)
}

View file

@ -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> {

View file

@ -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>;
}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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
View 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
View 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)
}
}

View file

@ -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