From 586aa6bae15b1ce7e854668b09da0f13542767d2 Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Fri, 2 Aug 2019 19:17:28 -0700 Subject: [PATCH] WIP - types check --- src/cli.rs | 8 ++--- src/commands.rs | 5 ++- src/commands/autoview.rs | 61 +++++++++++++++++++------------ src/commands/clip.rs | 2 +- src/commands/command.rs | 75 +++++++++++++++++++++++++++++++++++++++ src/commands/config.rs | 1 - src/commands/open.rs | 1 - src/commands/rm.rs | 1 - src/commands/save.rs | 18 ++++------ src/commands/table.rs | 45 ++++++++++++++++++----- src/commands/vtable.rs | 44 ++++++++++++++++++----- src/commands/where_.rs | 4 +-- src/context.rs | 2 +- src/format/table.rs | 2 +- src/parser/registry.rs | 5 --- src/plugins/add.rs | 5 ++- src/plugins/binaryview.rs | 4 +-- src/plugins/edit.rs | 5 ++- src/plugins/inc.rs | 5 ++- src/plugins/skip.rs | 5 ++- src/plugins/tree.rs | 3 +- src/prelude.rs | 1 + src/stream.rs | 26 +++++++++++++- 23 files changed, 239 insertions(+), 89 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 02dd5de13b..c8c283f1c4 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -175,9 +175,9 @@ pub async fn cli() -> Result<(), Box> { static_command(SkipWhile), static_command(Clip), static_command(Autoview), - // command("save", Box::new(save::save)), - // command("table", Box::new(table::table)), - // command("vtable", Box::new(vtable::vtable)), + static_command(Save), + static_command(Table), + static_command(VTable), ]); } let _ = load_plugins(&mut context); @@ -337,7 +337,7 @@ async fn process_line(readline: Result, ctx: &mut Context .push(ClassifiedCommand::Internal(InternalCommand { command: static_command(autoview::Autoview), name_span: None, - source_map: ctx.source_map, + source_map: ctx.source_map.clone(), args: hir::Call::new( Box::new(hir::Expression::synthetic_string("autoview")), None, diff --git a/src/commands.rs b/src/commands.rs index 1d0c5663b0..41b7b81bd9 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -47,11 +47,14 @@ crate use cd::Cd; crate use clip::Clip; crate use command::{ command, static_command, CallInfo, Command, CommandArgs, EvaluatedStaticCommandArgs, - StaticCommand, UnevaluatedCallInfo, + RawCommandArgs, StaticCommand, UnevaluatedCallInfo, }; crate use config::Config; crate use get::Get; 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; diff --git a/src/commands/autoview.rs b/src/commands/autoview.rs index d580294bc3..5715491e6b 100644 --- a/src/commands/autoview.rs +++ b/src/commands/autoview.rs @@ -1,4 +1,4 @@ -use crate::commands::StaticCommand; +use crate::commands::{RawCommandArgs, StaticCommand}; use crate::context::{SourceMap, SpanSource}; use crate::errors::ShellError; use crate::format::GenericView; @@ -7,6 +7,9 @@ use std::path::Path; pub struct Autoview; +#[derive(Deserialize)] +pub struct AutoviewArgs {} + impl StaticCommand for Autoview { fn name(&self) -> &str { "autoview" @@ -17,37 +20,49 @@ impl StaticCommand for Autoview { args: CommandArgs, registry: &CommandRegistry, ) -> Result { - args.process(registry, autoview)?.run() + args.process_raw(registry, autoview)?.run() } fn signature(&self) -> Signature { - Signature::build("autoview").sink() + Signature::build("autoview") } } -pub fn autoview(args: (), context: RunnableContext) -> Result { - if args.input.len() > 0 { - if let Spanned { - item: Value::Binary(_), - .. - } = args.input[0] - { - args.ctx.get_sink("binaryview").run(args)?; - } else if is_single_text_value(&args.input) { - view_text_value(&args.input[0], &args.call_info.source_map); - } 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 fn autoview( + AutoviewArgs {}: AutoviewArgs, + mut context: RunnableContext, + raw: RawCommandArgs, +) -> Result { + let stream = async_stream_block! { + let input = context.input.drain_vec().await; + + if input.len() > 0 { + if let Spanned { + item: Value::Binary(_), + .. + } = input[0] + { + let binary = context.expect_command("binaryview"); + binary.run(raw.with_input(input), &context.commands).await; + } else if is_single_text_value(&input) { + view_text_value(&input[0], &raw.call_info.source_map); + } else if equal_shapes(&input) { + let table = context.expect_command("table"); + table.run(raw.with_input(input), &context.commands).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(""); + // } } } - } + }; - Ok(OutputStream::empty()) + Ok(OutputStream::new(stream)) } fn equal_shapes(input: &Vec>) -> bool { diff --git a/src/commands/clip.rs b/src/commands/clip.rs index 0c07e80813..3601b76f27 100644 --- a/src/commands/clip.rs +++ b/src/commands/clip.rs @@ -24,7 +24,7 @@ impl StaticCommand for Clip { } fn signature(&self) -> Signature { - Signature::build("clip").sink() + Signature::build("clip") } } diff --git a/src/commands/command.rs b/src/commands/command.rs index b1622b7b44..5b8ee7de82 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -59,6 +59,25 @@ pub struct CommandArgs { pub input: InputStream, } +#[derive(Getters)] +#[get = "crate"] +pub struct RawCommandArgs { + pub host: Arc>, + pub env: Arc>, + pub call_info: UnevaluatedCallInfo, +} + +impl RawCommandArgs { + pub fn with_input(self, input: Vec>) -> CommandArgs { + CommandArgs { + host: self.host, + env: self.env, + 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) @@ -88,6 +107,7 @@ impl CommandArgs { callback: fn(T, RunnableContext) -> Result, ) -> Result, ShellError> { let env = self.env.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; @@ -97,12 +117,46 @@ impl CommandArgs { args: T::deserialize(&mut deserializer)?, context: RunnableContext { input: input, + commands: registry.clone(), env, name: name_span, + host, }, callback, }) } + + pub fn process_raw<'de, T: Deserialize<'de>>( + self, + registry: &CommandRegistry, + callback: fn(T, RunnableContext, RawCommandArgs) -> Result, + ) -> Result, ShellError> { + let raw_args = RawCommandArgs { + host: self.host.clone(), + env: self.env.clone(), + call_info: self.call_info.clone(), + }; + + let env = self.env.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(), + env, + name: name_span, + host, + }, + raw_args, + callback, + }) + } } pub struct SinkContext { @@ -120,6 +174,8 @@ pub struct SinkArgs { pub struct RunnableContext { pub input: InputStream, pub env: Arc>, + pub host: Arc>, + pub commands: CommandRegistry, pub name: Option, } @@ -130,6 +186,12 @@ impl RunnableContext { env.path.clone() } + + pub fn expect_command(&self, name: &str) -> Arc { + self.commands + .get_command(name) + .expect(&format!("Expected command {}", name)) + } } pub struct RunnableArgs { @@ -144,6 +206,19 @@ impl RunnableArgs { } } +pub struct RunnableRawArgs { + args: T, + raw_args: RawCommandArgs, + context: RunnableContext, + callback: fn(T, RunnableContext, RawCommandArgs) -> Result, +} + +impl RunnableRawArgs { + pub fn run(self) -> Result { + (self.callback)(self.args, self.context, self.raw_args) + } +} + pub struct EvaluatedStaticCommandArgs { pub args: EvaluatedCommandArgs, pub input: InputStream, diff --git a/src/commands/config.rs b/src/commands/config.rs index c0d8334023..a10ec1cd3b 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -30,7 +30,6 @@ impl StaticCommand for Config { .named("remove", SyntaxType::Any) .switch("clear") .switch("path") - .sink() } fn run( diff --git a/src/commands/open.rs b/src/commands/open.rs index 3739e46b12..c40e199d4d 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -28,7 +28,6 @@ impl StaticCommand for Open { Signature::build(self.name()) .required("path", SyntaxType::Block) .switch("raw") - .sink() } fn run( diff --git a/src/commands/rm.rs b/src/commands/rm.rs index 44403a078e..8bc17573e1 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -23,7 +23,6 @@ impl StaticCommand for Remove { Signature::build("rm") .required("path", SyntaxType::Path) .switch("recursive") - .sink() } fn run( diff --git a/src/commands/save.rs b/src/commands/save.rs index 47b838923e..dae51c9f00 100644 --- a/src/commands/save.rs +++ b/src/commands/save.rs @@ -7,13 +7,12 @@ use crate::errors::ShellError; use crate::object::{Primitive, Value}; use crate::parser::Spanned; use crate::prelude::*; -use futures_async_stream::async_stream_block; use std::path::{Path, PathBuf}; pub struct Save; #[derive(Deserialize)] -struct SaveArgs { +pub struct SaveArgs { path: Spanned, raw: bool, } @@ -27,7 +26,6 @@ impl StaticCommand for Save { Signature::build("save") .required("path", SyntaxType::Path) .switch("raw") - .sink() } fn run( @@ -55,7 +53,7 @@ pub fn save( let contents = match full_path.extension() { Some(x) if x == "csv" && !save_raw => { if input.len() != 1 { - return Err(ShellError::string( + yield Err(ShellError::string( "saving to csv requires a single object (or use --raw)", )); } @@ -63,7 +61,7 @@ pub fn save( } Some(x) if x == "toml" && !save_raw => { if input.len() != 1 { - return Err(ShellError::string( + yield Err(ShellError::string( "saving to toml requires a single object (or use --raw)", )); } @@ -71,7 +69,7 @@ pub fn save( } Some(x) if x == "json" && !save_raw => { if input.len() != 1 { - return Err(ShellError::string( + yield Err(ShellError::string( "saving to json requires a single object (or use --raw)", )); } @@ -79,7 +77,7 @@ pub fn save( } Some(x) if x == "yml" && !save_raw => { if input.len() != 1 { - return Err(ShellError::string( + yield Err(ShellError::string( "saving to yml requires a single object (or use --raw)", )); } @@ -87,7 +85,7 @@ pub fn save( } Some(x) if x == "yaml" && !save_raw => { if input.len() != 1 { - return Err(ShellError::string( + yield Err(ShellError::string( "saving to yaml requires a single object (or use --raw)", )); } @@ -113,7 +111,5 @@ pub fn save( let _ = std::fs::write(full_path, contents); }; - let stream: BoxStream<'static, ReturnValue> = stream.boxed(); - - Ok(OutputStream::from(stream)) + Ok(OutputStream::new(stream)) } diff --git a/src/commands/table.rs b/src/commands/table.rs index 02ce7cd384..a210e5842c 100644 --- a/src/commands/table.rs +++ b/src/commands/table.rs @@ -1,15 +1,42 @@ +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: CommandArgs, context: RunnableContext) -> 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 { + args.process(registry, table)?.run() + } + fn signature(&self) -> Signature { + Signature::build("table") } - - Ok(()) +} + +pub fn table(_args: TableArgs, context: RunnableContext) -> Result { + let stream = async_stream_block! { + let input: Vec> = context.input.into_vec().await; + if input.len() > 0 { + let mut host = context.host.lock().unwrap(); + let view = TableView::from_list(&input); + println!("{:#?}", view); + if let Some(view) = view { + handle_unexpected(&mut *host, |host| crate::format::print_view(&view, host)); + } + } + }; + + Ok(OutputStream::new(stream)) } diff --git a/src/commands/vtable.rs b/src/commands/vtable.rs index deb67b9d22..6ff1367d34 100644 --- a/src/commands/vtable.rs +++ b/src/commands/vtable.rs @@ -1,15 +1,41 @@ +use crate::commands::StaticCommand; use crate::errors::ShellError; use crate::format::VTableView; use crate::prelude::*; -pub fn vtable(args: CommandArgs, context: RunnableContext) -> 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 { + args.process(registry, vtable)?.run() + } + fn signature(&self) -> Signature { + Signature::build("vtable") + } +} + +pub fn vtable(args: VTableArgs, context: RunnableContext) -> Result { + 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)) } diff --git a/src/commands/where_.rs b/src/commands/where_.rs index 14b899c836..b5f5aaa5ee 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -21,9 +21,7 @@ impl StaticCommand for Where { } fn signature(&self) -> registry::Signature { - Signature::build("where") - .required("condition", SyntaxType::Block) - .sink() + Signature::build("where").required("condition", SyntaxType::Block) } fn run( diff --git a/src/context.rs b/src/context.rs index 75053f0c5d..9348e41840 100644 --- a/src/context.rs +++ b/src/context.rs @@ -47,7 +47,7 @@ impl CommandRegistry { } } - fn get_command(&self, name: &str) -> Option> { + crate fn get_command(&self, name: &str) -> Option> { let registry = self.registry.lock().unwrap(); registry.get(name).map(|c| c.clone()) diff --git a/src/format/table.rs b/src/format/table.rs index 4c71879f84..4618b23603 100644 --- a/src/format/table.rs +++ b/src/format/table.rs @@ -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, entries: Vec>, diff --git a/src/parser/registry.rs b/src/parser/registry.rs index 3a7cb96a18..f487a95f9d 100644 --- a/src/parser/registry.rs +++ b/src/parser/registry.rs @@ -125,11 +125,6 @@ impl Signature { self } - pub fn sink(mut self) -> Signature { - self.is_sink = true; - self - } - pub fn filter(mut self) -> Signature { self.is_filter = true; self diff --git a/src/plugins/add.rs b/src/plugins/add.rs index 6b5e2074ec..ae36903326 100644 --- a/src/plugins/add.rs +++ b/src/plugins/add.rs @@ -1,7 +1,7 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, CallInfo, Signature, Plugin, PositionalType, Primitive, ReturnSuccess, - ReturnValue, ShellError, Spanned, Value, + serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue, + ShellError, Signature, Spanned, Value, }; struct Add { @@ -48,7 +48,6 @@ impl Plugin for Add { PositionalType::mandatory_any("Value"), ], is_filter: true, - is_sink: false, named: IndexMap::new(), rest_positional: true, }) diff --git a/src/plugins/binaryview.rs b/src/plugins/binaryview.rs index be07a8ea26..09e6dca53f 100644 --- a/src/plugins/binaryview.rs +++ b/src/plugins/binaryview.rs @@ -2,8 +2,7 @@ use crossterm::{cursor, terminal, Attribute, RawScreen}; use indexmap::IndexMap; use nu::{ - serve_plugin, CallInfo, Signature, NamedType, Plugin, ShellError, SpanSource, Spanned, - Value, + serve_plugin, CallInfo, NamedType, Plugin, ShellError, Signature, SpanSource, Spanned, Value, }; use pretty_hex::*; @@ -23,7 +22,6 @@ impl Plugin for BinaryView { name: "binaryview".to_string(), positional: vec![], is_filter: false, - is_sink: true, named, rest_positional: false, }) diff --git a/src/plugins/edit.rs b/src/plugins/edit.rs index a5a70936b1..8348c706fa 100644 --- a/src/plugins/edit.rs +++ b/src/plugins/edit.rs @@ -1,7 +1,7 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, CallInfo, Signature, Plugin, PositionalType, Primitive, ReturnSuccess, - ReturnValue, ShellError, Spanned, Value, + serve_plugin, CallInfo, Plugin, PositionalType, Primitive, ReturnSuccess, ReturnValue, + ShellError, Signature, Spanned, Value, }; struct Edit { @@ -48,7 +48,6 @@ impl Plugin for Edit { PositionalType::mandatory_any("Value"), ], is_filter: true, - is_sink: false, named: IndexMap::new(), rest_positional: true, }) diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index 9c76da1173..6042ccba1a 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -1,7 +1,7 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, CallInfo, Signature, NamedType, Plugin, PositionalType, Primitive, - ReturnSuccess, ReturnValue, ShellError, Spanned, SpannedItem, Value, + serve_plugin, CallInfo, NamedType, Plugin, PositionalType, Primitive, ReturnSuccess, + ReturnValue, ShellError, Signature, Spanned, SpannedItem, Value, }; struct Inc { @@ -94,7 +94,6 @@ impl Plugin for Inc { name: "inc".to_string(), positional: vec![PositionalType::optional_any("Field")], is_filter: true, - is_sink: false, named, rest_positional: true, }) diff --git a/src/plugins/skip.rs b/src/plugins/skip.rs index 8fb1416647..2ff423bb03 100644 --- a/src/plugins/skip.rs +++ b/src/plugins/skip.rs @@ -1,7 +1,7 @@ use indexmap::IndexMap; use nu::{ - serve_plugin, CallInfo, Signature, Plugin, Primitive, ReturnSuccess, ReturnValue, - ShellError, Spanned, Value, + serve_plugin, CallInfo, Plugin, Primitive, ReturnSuccess, ReturnValue, ShellError, Signature, + Spanned, Value, }; struct NewSkip { @@ -19,7 +19,6 @@ impl Plugin for NewSkip { name: "skip".to_string(), positional: vec![], is_filter: true, - is_sink: false, named: IndexMap::new(), rest_positional: true, }) diff --git a/src/plugins/tree.rs b/src/plugins/tree.rs index f7b67efe39..f217bb0372 100644 --- a/src/plugins/tree.rs +++ b/src/plugins/tree.rs @@ -1,6 +1,6 @@ use derive_new::new; use indexmap::IndexMap; -use nu::{serve_plugin, CallInfo, Signature, Plugin, ShellError, Spanned, Value}; +use nu::{serve_plugin, CallInfo, Plugin, ShellError, Signature, Spanned, Value}; use ptree::item::StringItem; use ptree::output::print_tree_with; use ptree::print_config::PrintConfig; @@ -85,7 +85,6 @@ impl Plugin for TreeViewer { name: "tree".to_string(), positional: vec![], is_filter: false, - is_sink: true, named: IndexMap::new(), rest_positional: true, }) diff --git a/src/prelude.rs b/src/prelude.rs index 472f8785b5..a280e5c0f3 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -50,6 +50,7 @@ crate use crate::traits::{HasSpan, ToDebug}; crate use crate::Text; crate use futures::stream::BoxStream; crate use futures::{FutureExt, Stream, StreamExt}; +crate use futures_async_stream::async_stream_block; crate use serde::{Deserialize, Serialize}; crate use std::collections::VecDeque; crate use std::future::Future; diff --git a/src/stream.rs b/src/stream.rs index 465dcf9fcf..dd37782c8d 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -9,6 +9,13 @@ impl InputStream { self.values.collect() } + pub fn drain_vec(&mut self) -> impl Future>> { + let mut values: BoxStream<'static, Spanned> = VecDeque::new().boxed(); + std::mem::swap(&mut values, &mut self.values); + + values.collect() + } + pub fn from_stream(input: impl Stream> + Send + 'static) -> InputStream { InputStream { values: input.boxed(), @@ -46,13 +53,19 @@ pub struct OutputStream { } impl OutputStream { + pub fn new(values: impl Stream + Send + 'static) -> OutputStream { + OutputStream { + values: values.boxed(), + } + } + pub fn empty() -> OutputStream { let v: VecDeque = VecDeque::new(); v.into() } pub fn one(item: impl Into) -> OutputStream { - let v: VecDeque = VecDeque::new(); + let mut v: VecDeque = VecDeque::new(); v.push_back(item.into()); v.into() } @@ -64,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> { + Stream::poll_next(std::pin::Pin::new(&mut self.values), cx) + } +} + impl From for OutputStream { fn from(input: InputStream) -> OutputStream { OutputStream {