From 0180769971f6e24388434d5dd6b9c3107e2ae732 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 4 Jul 2019 05:37:09 +1200 Subject: [PATCH] WIP now load plugins automatically --- Cargo.lock | 1 + Cargo.toml | 5 + src/cli.rs | 201 +++++++++++++++++++++++++++++--------- src/commands/command.rs | 11 ++- src/commands/from_ini.rs | 9 +- src/commands/from_json.rs | 7 +- src/commands/from_toml.rs | 7 +- src/commands/from_xml.rs | 7 +- src/commands/from_yaml.rs | 7 +- src/commands/plugin.rs | 40 ++++---- src/commands/to_json.rs | 2 +- src/commands/to_toml.rs | 2 +- src/format/entries.rs | 18 +--- src/format/table.rs | 12 +-- src/format/tree.rs | 4 +- src/format/vtable.rs | 8 +- src/lib.rs | 2 +- src/object.rs | 2 - src/object/base.rs | 41 ++++---- src/object/desc.rs | 134 ------------------------- src/object/dict.rs | 54 +++------- src/plugin.rs | 8 +- src/plugins/inc.rs | 19 +++- src/plugins/newskip.rs | 59 +++++++++++ src/plugins/sum.rs | 17 +++- 25 files changed, 348 insertions(+), 329 deletions(-) delete mode 100644 src/object/desc.rs create mode 100644 src/plugins/newskip.rs diff --git a/Cargo.lock b/Cargo.lock index a6feec745f..8c4808fe70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1492,6 +1492,7 @@ dependencies = [ "toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 18e2bf9d4d..695cef75e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ serde_ini = "0.2.0" subprocess = "0.1.18" sys-info = "0.5.7" mime = "0.3.13" +walkdir = "2.2.8" [dev-dependencies] pretty_assertions = "0.6.1" @@ -79,6 +80,10 @@ path = "src/plugins/sum.rs" name = "nu_plugin_inc" path = "src/plugins/inc.rs" +[[bin]] +name = "nu_plugin_newskip" +path = "src/plugins/newskip.rs" + [[bin]] name = "nu" path = "src/main.rs" diff --git a/src/cli.rs b/src/cli.rs index a59aef3216..b205ec3a7e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,30 +1,31 @@ use crate::commands::autoview; use crate::commands::classified::SinkCommand; -use crate::commands::command::sink; - -use crate::prelude::*; - use crate::commands::classified::{ ClassifiedCommand, ClassifiedInputStream, ClassifiedPipeline, ExternalCommand, InternalCommand, StreamNext, }; +use crate::commands::command::sink; +use crate::commands::plugin::{JsonRpc, NuResult}; use crate::context::Context; crate use crate::errors::ShellError; use crate::evaluate::Scope; -use crate::parser::parse::span::Spanned; -use crate::parser::registry; -use crate::parser::{Pipeline, PipelineElement, TokenNode}; - use crate::git::current_branch; use crate::object::Value; +use crate::parser::parse::span::Spanned; +use crate::parser::registry; +use crate::parser::registry::CommandConfig; +use crate::parser::{Pipeline, PipelineElement, TokenNode}; +use crate::prelude::*; use log::{debug, trace}; use rustyline::error::ReadlineError; use rustyline::{self, ColorMode, Config, Editor}; - +use std::env; use std::error::Error; +use std::io::{BufRead, BufReader, Write}; use std::iter::Iterator; use std::sync::atomic::{AtomicBool, Ordering}; +use walkdir::WalkDir; #[derive(Debug)] pub enum MaybeOwned<'a, T> { @@ -41,6 +42,112 @@ impl MaybeOwned<'a, T> { } } +fn load_plugin(fname: &str, context: &mut Context) -> Result<(), ShellError> { + use crate::commands::{command, plugin}; + + println!("fname: {}", fname); + let mut child = std::process::Command::new(fname) + .stdin(std::process::Stdio::piped()) + .stdout(std::process::Stdio::piped()) + .spawn() + .expect("Failed to spawn child process"); + + let stdin = child.stdin.as_mut().expect("Failed to open stdin"); + let stdout = child.stdout.as_mut().expect("Failed to open stdout"); + + let mut reader = BufReader::new(stdout); + + println!("Sending out config request"); + + let request = JsonRpc::new("config", Vec::::new()); + let request_raw = serde_json::to_string(&request).unwrap(); + stdin.write(format!("{}\n", request_raw).as_bytes())?; + + let mut input = String::new(); + match reader.read_line(&mut input) { + Ok(_) => { + println!("Got a response!: {}", input); + let response = + serde_json::from_str::>>(&input); + match response { + Ok(jrpc) => match jrpc.params { + Ok(params) => { + println!("Loaded: {}", params.name); + if params.is_filter { + let fname = fname.to_string(); + context.add_commands(vec![command( + ¶ms.name, + Box::new(move |x| plugin::filter_plugin(fname.clone(), x)), + )]); + Ok(()) + } else if params.is_sink { + let fname = fname.to_string(); + context.add_sinks(vec![sink( + ¶ms.name, + Box::new(move |x| plugin::sink_plugin(fname.clone(), x)), + )]); + Ok(()) + } else { + Ok(()) + } + } + Err(e) => Err(e), + }, + Err(e) => Err(ShellError::string(format!("Error: {:?}", e))), + } + } + Err(e) => Err(ShellError::string(format!("Error: {:?}", e))), + } +} + +fn load_plugins(context: &mut Context) -> Result<(), ShellError> { + match env::var_os("PATH") { + Some(paths) => { + //println!("{:?}", paths); + for path in env::split_paths(&paths) { + match std::fs::read_dir(path) { + Ok(path) => { + for entry in path { + let entry = entry.unwrap(); + let filename = entry.file_name(); + let f_name = filename.to_string_lossy(); + if f_name.starts_with("nu_plugin_") && !f_name.ends_with(".d") { + //println!("Found: {}", f_name); + load_plugin(&f_name, context)?; + } + } + } + _ => {} + } + } + } + None => println!("PATH is not defined in the environment."), + } + + // Also use our debug output for now + let mut path = std::path::PathBuf::from("."); + path.push("target"); + path.push("debug"); + + match std::fs::read_dir(path) { + Ok(path) => { + for entry in path { + let entry = entry.unwrap(); + let filename = entry.file_name(); + let f_name = filename.to_string_lossy(); + println!("looking at: {}", f_name); + if f_name.starts_with("nu_plugin_") && !f_name.ends_with(".d") { + println!("Found: {}", f_name); + load_plugin(&entry.path().to_string_lossy(), context)?; + } + } + } + _ => {} + } + + Ok(()) +} + pub async fn cli() -> Result<(), Box> { let mut context = Context::basic()?; @@ -48,51 +155,55 @@ pub async fn cli() -> Result<(), Box> { use crate::commands::*; context.add_commands(vec![ - command("ps", ps::ps), - command("ls", ls::ls), - command("sysinfo", sysinfo::sysinfo), - command("cd", cd::cd), - command("view", view::view), - command("skip", skip::skip), - command("first", first::first), - command("size", size::size), - command("from-ini", from_ini::from_ini), - command("from-json", from_json::from_json), - command("from-toml", from_toml::from_toml), - command("from-xml", from_xml::from_xml), - command("from-yaml", from_yaml::from_yaml), - command("get", get::get), - command("enter", enter::enter), - command("exit", exit::exit), - command("lines", lines::lines), - command("pick", pick::pick), - command("split-column", split_column::split_column), - command("split-row", split_row::split_row), - command("lines", lines::lines), - command("reject", reject::reject), - command("trim", trim::trim), - command("to-array", to_array::to_array), - command("to-json", to_json::to_json), - command("to-toml", to_toml::to_toml), - command("sort-by", sort_by::sort_by), + command("ps", Box::new(ps::ps)), + command("ls", Box::new(ls::ls)), + command("sysinfo", Box::new(sysinfo::sysinfo)), + command("cd", Box::new(cd::cd)), + command("view", Box::new(view::view)), + command("skip", Box::new(skip::skip)), + command("first", Box::new(first::first)), + command("size", Box::new(size::size)), + command("from-ini", Box::new(from_ini::from_ini)), + 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("from-yaml", Box::new(from_yaml::from_yaml)), + command("get", Box::new(get::get)), + command("enter", Box::new(enter::enter)), + command("exit", Box::new(exit::exit)), + command("lines", Box::new(lines::lines)), + command("pick", Box::new(pick::pick)), + command("split-column", Box::new(split_column::split_column)), + command("split-row", Box::new(split_row::split_row)), + command("lines", Box::new(lines::lines)), + command("reject", Box::new(reject::reject)), + command("trim", Box::new(trim::trim)), + command("to-array", Box::new(to_array::to_array)), + command("to-json", Box::new(to_json::to_json)), + command("to-toml", Box::new(to_toml::to_toml)), + command("sort-by", Box::new(sort_by::sort_by)), Arc::new(Open), Arc::new(Where), Arc::new(Config), Arc::new(SkipWhile), - command("sort-by", sort_by::sort_by), + command("sort-by", Box::new(sort_by::sort_by)), + /* command("inc", |x| plugin::filter_plugin("inc".into(), x)), + command("newskip", |x| plugin::filter_plugin("newskip".into(), x)), + */ ]); context.add_sinks(vec![ - sink("autoview", autoview::autoview), - sink("clip", clip::clip), - sink("save", save::save), - sink("table", table::table), - sink("tree", tree::tree), - sink("vtable", vtable::vtable), - sink("sum", |x| plugin::sink_plugin("sum".into(), x)), + sink("autoview", Box::new(autoview::autoview)), + sink("clip", Box::new(clip::clip)), + sink("save", Box::new(save::save)), + sink("table", Box::new(table::table)), + sink("tree", Box::new(tree::tree)), + sink("vtable", Box::new(vtable::vtable)), + //sink("sum", |x| plugin::sink_plugin("sum".into(), x)), ]); } + load_plugins(&mut context); let config = Config::builder().color_mode(ColorMode::Forced).build(); let h = crate::shell::Helper::new(context.clone_commands()); @@ -250,7 +361,7 @@ async fn process_line(readline: Result, ctx: &mut Context Some(ClassifiedCommand::Sink(_)) => {} Some(ClassifiedCommand::External(_)) => {} _ => pipeline.commands.push(ClassifiedCommand::Sink(SinkCommand { - command: sink("autoview", autoview::autoview), + command: sink("autoview", Box::new(autoview::autoview)), name_span: None, args: registry::Args { positional: None, diff --git a/src/commands/command.rs b/src/commands/command.rs index e9eac51b58..31d5723284 100644 --- a/src/commands/command.rs +++ b/src/commands/command.rs @@ -111,7 +111,7 @@ pub trait Sink { pub struct FnCommand { name: String, - func: fn(CommandArgs) -> Result, + func: Box Result>, } impl Command for FnCommand { @@ -126,7 +126,7 @@ impl Command for FnCommand { pub fn command( name: &str, - func: fn(CommandArgs) -> Result, + func: Box Result>, ) -> Arc { Arc::new(FnCommand { name: name.to_string(), @@ -136,7 +136,7 @@ pub fn command( pub struct FnSink { name: String, - func: fn(SinkCommandArgs) -> Result<(), ShellError>, + func: Box Result<(), ShellError>>, } impl Sink for FnSink { @@ -149,7 +149,10 @@ impl Sink for FnSink { } } -pub fn sink(name: &str, func: fn(SinkCommandArgs) -> Result<(), ShellError>) -> Arc { +pub fn sink( + name: &str, + func: Box Result<(), ShellError>>, +) -> Arc { Arc::new(FnSink { name: name.to_string(), func, diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index fd14101367..4e8701d98e 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -1,4 +1,4 @@ -use crate::object::{DataDescriptor, Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, Value}; use crate::prelude::*; use indexmap::IndexMap; use std::collections::HashMap; @@ -7,7 +7,7 @@ fn convert_ini_second_to_nu_value(v: &HashMap) -> Value { let mut second = Dictionary::new(IndexMap::new()); for (key, value) in v.into_iter() { second.add( - DataDescriptor::from(key.as_str()), + key.clone(), Value::Primitive(Primitive::String(value.clone())), ); } @@ -16,10 +16,7 @@ fn convert_ini_second_to_nu_value(v: &HashMap) -> Value { fn convert_ini_top_to_nu_value(v: &HashMap>) -> Value { let mut top_level = Dictionary::new(IndexMap::new()); for (key, value) in v.iter() { - top_level.add( - DataDescriptor::from(key.as_str()), - convert_ini_second_to_nu_value(value), - ); + top_level.add(key.clone(), convert_ini_second_to_nu_value(value)); } Value::Object(top_level) } diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index 9f344c01fe..e85d19d684 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -1,5 +1,5 @@ use crate::object::base::OF64; -use crate::object::{DataDescriptor, Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, Value}; use crate::prelude::*; fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value { @@ -18,10 +18,7 @@ fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value { serde_hjson::Value::Object(o) => { let mut collected = Dictionary::default(); for (k, v) in o.iter() { - collected.add( - DataDescriptor::from(k.clone()), - convert_json_value_to_nu_value(v), - ); + collected.add(k.clone(), convert_json_value_to_nu_value(v)); } Value::Object(collected) } diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index 4d9f3b735e..5d1bb9a0c0 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -1,5 +1,5 @@ use crate::object::base::OF64; -use crate::object::{DataDescriptor, Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, Value}; use crate::prelude::*; fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value { @@ -17,10 +17,7 @@ fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value { toml::Value::Table(t) => { let mut collected = Dictionary::default(); for (k, v) in t.iter() { - collected.add( - DataDescriptor::from(k.clone()), - convert_toml_value_to_nu_value(v), - ); + collected.add(k.clone(), convert_toml_value_to_nu_value(v)); } Value::Object(collected) } diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index 66b4adf28c..d7c8091f8e 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -1,4 +1,4 @@ -use crate::object::{DataDescriptor, Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, Value}; use crate::prelude::*; fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { @@ -25,10 +25,7 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { .collect(); let mut collected = Dictionary::default(); - collected.add( - DataDescriptor::from(name.clone()), - Value::List(children_values), - ); + collected.add(name.clone(), Value::List(children_values)); Value::Object(collected) } else if n.is_comment() { diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index 6aa5ab0af5..2a07d47d1f 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -1,5 +1,5 @@ use crate::object::base::OF64; -use crate::object::{DataDescriptor, Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, Value}; use crate::prelude::*; fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value { @@ -22,10 +22,7 @@ fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value { for (k, v) in t.iter() { match k { serde_yaml::Value::String(k) => { - collected.add( - DataDescriptor::from(k.clone()), - convert_yaml_value_to_nu_value(v), - ); + collected.add(k.clone(), convert_yaml_value_to_nu_value(v)); } _ => unimplemented!("Unknown key type"), } diff --git a/src/commands/plugin.rs b/src/commands/plugin.rs index 60b972ad38..dad8459410 100644 --- a/src/commands/plugin.rs +++ b/src/commands/plugin.rs @@ -32,17 +32,17 @@ pub enum NuResult { }, } -pub fn filter_plugin(plugin_name: String, args: CommandArgs) -> Result { - let mut path = std::path::PathBuf::from("."); - path.push("target"); - path.push("debug"); - path.push(format!("nu_plugin_{}", plugin_name)); +pub fn filter_plugin(path: String, args: CommandArgs) -> Result { + //let mut path = std::path::PathBuf::from("."); + //path.push("target"); + //path.push("debug"); + //path.push(format!("nu_plugin_{}", plugin_name)); - path = if path.exists() { - path - } else { - std::path::PathBuf::from(format!("nu_plugin_{}", plugin_name)) - }; + // path = if path.exists() { + // path + // } else { + // std::path::PathBuf::from(format!("nu_plugin_{}", plugin_name)) + // }; let mut child = std::process::Command::new(path) .stdin(std::process::Stdio::piped()) @@ -129,17 +129,17 @@ pub fn filter_plugin(plugin_name: String, args: CommandArgs) -> Result Result<(), ShellError> { - let mut path = std::path::PathBuf::from("."); - path.push("target"); - path.push("debug"); - path.push(format!("nu_plugin_{}", plugin_name)); +pub fn sink_plugin(path: String, args: SinkCommandArgs) -> Result<(), ShellError> { + // let mut path = std::path::PathBuf::from("."); + // path.push("target"); + // path.push("debug"); + // path.push(format!("nu_plugin_{}", plugin_name)); - path = if path.exists() { - path - } else { - std::path::PathBuf::from(format!("nu_plugin_{}", plugin_name)) - }; + // path = if path.exists() { + // path + // } else { + // std::path::PathBuf::from(format!("nu_plugin_{}", plugin_name)) + // }; let mut child = std::process::Command::new(path) .stdin(std::process::Stdio::piped()) diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 51dee4fd6a..8d78ad9ace 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -27,7 +27,7 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value { Value::Object(o) => { let mut m = serde_json::Map::new(); for (k, v) in o.entries.iter() { - m.insert(k.name.display().to_string(), value_to_json_value(v)); + m.insert(k.clone(), value_to_json_value(v)); } serde_json::Value::Object(m) } diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 4818ddd915..256dde52db 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -21,7 +21,7 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value { Value::Object(o) => { let mut m = toml::map::Map::new(); for (k, v) in o.entries.iter() { - m.insert(k.name.display().to_string(), value_to_toml_value(v)); + m.insert(k.clone(), value_to_toml_value(v)); } toml::Value::Table(m) } diff --git a/src/format/entries.rs b/src/format/entries.rs index a39462caa0..67855beedc 100644 --- a/src/format/entries.rs +++ b/src/format/entries.rs @@ -10,7 +10,7 @@ use derive_new::new; // another_name : ... #[derive(new)] pub struct EntriesView { - entries: Vec<(crate::object::DescriptorName, String)>, + entries: Vec<(String, String)>, } impl EntriesView { @@ -23,7 +23,7 @@ impl EntriesView { let formatted_value = value.borrow().format_leaf(None); - entries.push((desc.name.clone(), formatted_value)) + entries.push((desc.clone(), formatted_value)) } EntriesView::new(entries) @@ -36,20 +36,10 @@ impl RenderView for EntriesView { return Ok(()); } - let max_name_size: usize = self - .entries - .iter() - .map(|(n, _)| n.display().len()) - .max() - .unwrap(); + let max_name_size: usize = self.entries.iter().map(|(n, _)| n.len()).max().unwrap(); for (name, value) in &self.entries { - println!( - "{:width$} : {}", - name.display(), - value, - width = max_name_size - ) + println!("{:width$} : {}", name, value, width = max_name_size) } Ok(()) diff --git a/src/format/table.rs b/src/format/table.rs index d3b585c7a1..6b2205c3f3 100644 --- a/src/format/table.rs +++ b/src/format/table.rs @@ -1,5 +1,5 @@ use crate::format::RenderView; -use crate::object::{DataDescriptor, Value}; +use crate::object::Value; use crate::prelude::*; use derive_new::new; use prettytable::format::{FormatBuilder, LinePosition, LineSeparator}; @@ -8,12 +8,12 @@ use prettytable::{color, Attr, Cell, Row, Table}; #[derive(new)] pub struct TableView { - headers: Vec, + headers: Vec, entries: Vec>, } impl TableView { - fn merge_descriptors(values: &[Value]) -> Vec { + fn merge_descriptors(values: &[Value]) -> Vec { let mut ret = vec![]; for value in values { for desc in value.data_descriptors() { @@ -30,10 +30,10 @@ impl TableView { return None; } - let headers = TableView::merge_descriptors(values); + let mut headers = TableView::merge_descriptors(values); if headers.len() == 0 { - return None; + headers.push("value".to_string()); } let mut entries = vec![]; @@ -74,7 +74,7 @@ impl RenderView for TableView { .headers .iter() .map(|h| { - Cell::new(h.display_header()) + Cell::new(h) .with_style(Attr::ForegroundColor(color::GREEN)) .with_style(Attr::Bold) }) diff --git a/src/format/tree.rs b/src/format/tree.rs index 6bf7206a94..e9a59e86a5 100644 --- a/src/format/tree.rs +++ b/src/format/tree.rs @@ -26,7 +26,7 @@ impl TreeView { } Value::Object(o) => { for (k, v) in o.entries.iter() { - builder = builder.begin_child(k.name.display().to_string()); + builder = builder.begin_child(k.clone()); Self::from_value_helper(v, builder); builder = builder.end_child(); } @@ -49,7 +49,7 @@ impl TreeView { for desc in descs { let value = value.get_data(&desc); - builder = builder.begin_child(desc.name.display().to_string()); + builder = builder.begin_child(desc.clone()); Self::from_value_helper(value.borrow(), &mut builder); builder = builder.end_child(); //entries.push((desc.name.clone(), value.borrow().copy())) diff --git a/src/format/vtable.rs b/src/format/vtable.rs index 86ddd62df7..9e658f5c84 100644 --- a/src/format/vtable.rs +++ b/src/format/vtable.rs @@ -1,5 +1,5 @@ use crate::format::RenderView; -use crate::object::{DescriptorName, Value}; +use crate::object::Value; use crate::prelude::*; use derive_new::new; use prettytable::format::{FormatBuilder, LinePosition, LineSeparator}; @@ -29,11 +29,7 @@ impl VTableView { for header in headers { let mut row = vec![]; - if let DescriptorName::String(s) = &header.name { - row.push(s.clone()); - } else { - row.push("value".to_string()); - } + row.push(header.clone()); for value in values { row.push(value.get_data(&header).borrow().format_leaf(Some(&header))); } diff --git a/src/lib.rs b/src/lib.rs index c843906722..49953b3c72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,4 +28,4 @@ pub use cli::cli; pub use errors::ShellError; pub use object::base::{Primitive, Value}; pub use parser::parse::text::Text; -pub use parser::registry::{Args, CommandConfig}; +pub use parser::registry::{Args, CommandConfig, NamedType, PositionalType}; diff --git a/src/object.rs b/src/object.rs index 3a54ea25c7..7e8be20e09 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,12 +1,10 @@ crate mod base; crate mod config; -crate mod desc; crate mod dict; crate mod files; crate mod process; crate mod types; crate use base::{Primitive, Value}; -crate use desc::{DataDescriptor, DescriptorName}; crate use dict::Dictionary; crate use files::dir_entry_dict; diff --git a/src/object/base.rs b/src/object/base.rs index e61e612ed2..d1dd7cfc4f 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -1,6 +1,5 @@ use crate::errors::ShellError; use crate::evaluate::{evaluate_baseline_expr, Scope}; -use crate::object::DataDescriptor; use crate::parser::{hir, Operator, Span, Spanned}; use crate::prelude::*; use crate::Text; @@ -76,7 +75,7 @@ impl Primitive { } } - crate fn format(&self, field_name: Option<&DataDescriptor>) -> String { + crate fn format(&self, field_name: Option<&String>) -> String { match self { Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")), Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")), @@ -100,8 +99,8 @@ impl Primitive { Primitive::Boolean(b) => match (b, field_name) { (true, None) => format!("Yes"), (false, None) => format!("No"), - (true, Some(s)) if s.is_string_name() => format!("{}", s.display_header()), - (false, Some(s)) if s.is_string_name() => format!(""), + (true, Some(s)) if !s.is_empty() => format!("{}", s), + (false, Some(s)) if !s.is_empty() => format!(""), (true, Some(_)) => format!("Yes"), (false, Some(_)) => format!("No"), }, @@ -245,13 +244,18 @@ impl Value { ValueDebug { value: self } } - crate fn data_descriptors(&self) -> Vec { + crate fn data_descriptors(&self) -> Vec { match self { - Value::Primitive(_) => vec![DataDescriptor::value_of()], - Value::Object(o) => o.data_descriptors(), - Value::Block(_) => vec![DataDescriptor::value_of()], + Value::Primitive(_) => vec![], + Value::Object(o) => o + .entries + .keys() + .into_iter() + .map(|x| x.to_string()) + .collect(), + Value::Block(_) => vec![], Value::List(_) => vec![], - Value::Error(_) => vec![DataDescriptor::value_of()], + Value::Error(_) => vec![], Value::Filesystem => vec![], } } @@ -282,7 +286,7 @@ impl Value { } } - crate fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> { + crate fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> { match self { p @ Value::Primitive(_) => MaybeOwned::Borrowed(p), p @ Value::Filesystem => MaybeOwned::Borrowed(p), @@ -307,7 +311,7 @@ impl Value { } } - crate fn format_leaf(&self, desc: Option<&DataDescriptor>) -> String { + crate fn format_leaf(&self, desc: Option<&String>) -> String { match self { Value::Primitive(p) => p.format(desc), Value::Block(b) => itertools::join( @@ -471,9 +475,9 @@ crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Diction let descs = obj.data_descriptors(); for field in fields { - match descs.iter().find(|d| d.name.is_string(field)) { - None => out.add(DataDescriptor::for_string_name(field), Value::nothing()), - Some(desc) => out.add(desc.copy(), obj.get_data(desc).borrow().copy()), + match descs.iter().find(|d| *d == field) { + None => out.add(field, Value::nothing()), + Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().copy()), } } @@ -486,10 +490,9 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction let descs = obj.data_descriptors(); for desc in descs { - match desc.name.as_string() { - None => continue, - Some(s) if fields.iter().any(|field| field == s) => continue, - Some(_) => out.add(desc.copy(), obj.get_data(&desc).borrow().copy()), + match desc { + x if fields.iter().any(|field| *field == x) => continue, + _ => out.add(desc.clone(), obj.get_data(&desc).borrow().copy()), } } @@ -499,7 +502,7 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction #[allow(unused)] crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool { let descs = obj.data_descriptors(); - match descs.iter().find(|d| d.name.is_string(field)) { + match descs.iter().find(|d| *d == field) { None => false, Some(desc) => { let v = obj.get_data(desc).borrow().copy(); diff --git a/src/object/desc.rs b/src/object/desc.rs deleted file mode 100644 index a3d7784a63..0000000000 --- a/src/object/desc.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::object::types::Type; -use crate::Text; -use derive_new::new; -use serde::{Deserialize, Serialize, Serializer}; - -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] -pub enum DescriptorName { - String(String), - ValueOf, -} - -impl DescriptorName { - crate fn display(&self) -> &str { - match self { - DescriptorName::String(s) => s, - DescriptorName::ValueOf => "value", - } - } - - crate fn debug(&self) -> &str { - match self { - DescriptorName::String(s) => s, - DescriptorName::ValueOf => "[[value]]", - } - } - - crate fn as_string(&self) -> Option<&str> { - match self { - DescriptorName::String(s) => Some(s), - DescriptorName::ValueOf => None, - } - } - - crate fn is_string(&self, string: &str) -> bool { - match self { - DescriptorName::String(s) => s == string, - DescriptorName::ValueOf => false, - } - } -} - -#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] -pub struct DataDescriptor { - crate name: DescriptorName, - crate readonly: bool, - crate ty: Type, -} - -impl DataDescriptor { - crate fn display_header(&self) -> &str { - self.name.display() - } - - crate fn is_string_name(&self) -> bool { - match self.name { - DescriptorName::String(_) => true, - DescriptorName::ValueOf => false, - } - } -} - -impl Serialize for DataDescriptor { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self.name { - DescriptorName::String(ref s) => serializer.serialize_str(s), - DescriptorName::ValueOf => serializer.serialize_str("value"), - } - } -} - -impl From<&str> for DataDescriptor { - fn from(input: &str) -> DataDescriptor { - DataDescriptor { - name: DescriptorName::String(input.to_string()), - readonly: true, - ty: Type::Any, - } - } -} - -impl From for DataDescriptor { - fn from(input: String) -> DataDescriptor { - DataDescriptor { - name: DescriptorName::String(input), - readonly: true, - ty: Type::Any, - } - } -} - -impl From for DataDescriptor { - fn from(input: Text) -> DataDescriptor { - DataDescriptor { - name: DescriptorName::String(input.to_string()), - readonly: true, - ty: Type::Any, - } - } -} - -impl DescriptorName { - crate fn for_string_name(name: impl AsRef) -> DescriptorName { - DescriptorName::String(name.as_ref().into()) - } -} - -impl DataDescriptor { - crate fn value_of() -> DataDescriptor { - DataDescriptor { - name: DescriptorName::ValueOf, - readonly: true, - ty: Type::Any, - } - } - - crate fn for_name(name: impl Into) -> DataDescriptor { - DataDescriptor { - name: name.into(), - readonly: true, - ty: Type::Any, - } - } - - crate fn for_string_name(name: impl AsRef) -> DataDescriptor { - DataDescriptor::for_name(DescriptorName::for_string_name(name)) - } - - crate fn copy(&self) -> DataDescriptor { - self.clone() - } -} diff --git a/src/object/dict.rs b/src/object/dict.rs index 146967c81c..225de4fe92 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -1,23 +1,21 @@ use crate::prelude::*; -use crate::object::DataDescriptor; use crate::object::{Primitive, Value}; use derive_new::new; use indexmap::IndexMap; -use serde::ser::{Serialize, SerializeMap, Serializer}; -use serde_derive::Deserialize; +use serde::{Deserialize, Serialize}; use std::cmp::{Ordering, PartialOrd}; use std::fmt; -#[derive(Debug, Default, Eq, PartialEq, Deserialize, Clone, new)] +#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)] pub struct Dictionary { - pub entries: IndexMap, + pub entries: IndexMap, } impl PartialOrd for Dictionary { fn partial_cmp(&self, other: &Dictionary) -> Option { - let this: Vec<&DataDescriptor> = self.entries.keys().collect(); - let that: Vec<&DataDescriptor> = other.entries.keys().collect(); + let this: Vec<&String> = self.entries.keys().collect(); + let that: Vec<&String> = other.entries.keys().collect(); if this != that { return this.partial_cmp(&that); @@ -30,34 +28,12 @@ impl PartialOrd for Dictionary { } } -impl Serialize for Dictionary { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut map = serializer.serialize_map(Some(self.entries.len()))?; - for (k, v) in self.entries.iter() { - match v { - Value::Object(_) => {} - _ => map.serialize_entry(k, v)?, - } - } - for (k, v) in self.entries.iter() { - match v { - Value::Object(_) => map.serialize_entry(k, v)?, - _ => {} - } - } - map.end() - } -} - impl From> for Dictionary { fn from(input: IndexMap) -> Dictionary { let mut out = IndexMap::default(); for (key, value) in input { - out.insert(DataDescriptor::for_string_name(key), value); + out.insert(key, value); } Dictionary::new(out) @@ -66,8 +42,8 @@ impl From> for Dictionary { impl Ord for Dictionary { fn cmp(&self, other: &Dictionary) -> Ordering { - let this: Vec<&DataDescriptor> = self.entries.keys().collect(); - let that: Vec<&DataDescriptor> = other.entries.keys().collect(); + let this: Vec<&String> = self.entries.keys().collect(); + let that: Vec<&String> = other.entries.keys().collect(); if this != that { return this.cmp(&that); @@ -96,7 +72,7 @@ impl PartialEq for Dictionary { } impl Dictionary { - crate fn add(&mut self, name: impl Into, value: Value) { + crate fn add(&mut self, name: impl Into, value: Value) { self.entries.insert(name.into(), value); } @@ -104,17 +80,13 @@ impl Dictionary { let mut out = Dictionary::default(); for (key, value) in self.entries.iter() { - out.add(key.copy(), value.copy()); + out.add(key.clone(), value.copy()); } out } - crate fn data_descriptors(&self) -> Vec { - self.entries.iter().map(|(name, _)| name.copy()).collect() - } - - crate fn get_data(&'a self, desc: &DataDescriptor) -> MaybeOwned<'a, Value> { + crate fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> { match self.entries.get(desc) { Some(v) => MaybeOwned::Borrowed(v), None => MaybeOwned::Owned(Value::Primitive(Primitive::Nothing)), @@ -125,7 +97,7 @@ impl Dictionary { match self .entries .iter() - .find(|(desc_name, _)| desc_name.name.is_string(name)) + .find(|(desc_name, _)| *desc_name == name) { Some((_, v)) => Some(v), None => None, @@ -136,7 +108,7 @@ impl Dictionary { let mut debug = f.debug_struct("Dictionary"); for (desc, value) in self.entries.iter() { - debug.field(desc.name.debug(), &value.debug()); + debug.field(desc, &value.debug()); } debug.finish() diff --git a/src/plugin.rs b/src/plugin.rs index 412e5aa8a7..688b448310 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -3,9 +3,7 @@ use serde::{Deserialize, Serialize}; use std::io; pub trait Plugin { - fn config(&mut self) -> Result { - Err(ShellError::string("`config` not implemented in plugin")) - } + fn config(&mut self) -> Result; #[allow(unused)] fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { Err(ShellError::string( @@ -50,8 +48,8 @@ pub fn serve_plugin(plugin: &mut dyn Plugin) { } e => { send_response(ShellError::string(format!( - "Could not handle plugin message: {:?}", - e, + "Could not handle plugin message: {} {:?}", + input, e ))); break; } diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index afb0abeaf0..a55c3d34f1 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -1,4 +1,8 @@ -use nu::{serve_plugin, Args, Plugin, Primitive, ReturnValue, ShellError, Spanned, Value}; +use indexmap::IndexMap; +use nu::{ + serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError, + Spanned, Value, +}; struct Inc { inc_by: i64, @@ -10,6 +14,19 @@ impl Inc { } impl Plugin for Inc { + fn config(&mut self) -> Result { + Ok(CommandConfig { + name: "inc".to_string(), + mandatory_positional: vec![], + optional_positional: vec![PositionalType::Value("Increment".into())], + can_load: vec![], + can_save: vec![], + is_filter: true, + is_sink: false, + named: IndexMap::new(), + rest_positional: true, + }) + } fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { if let Some(args) = args.positional { for arg in args { diff --git a/src/plugins/newskip.rs b/src/plugins/newskip.rs new file mode 100644 index 0000000000..14e3a5dee6 --- /dev/null +++ b/src/plugins/newskip.rs @@ -0,0 +1,59 @@ +use indexmap::IndexMap; +use nu::{ + serve_plugin, Args, CommandConfig, Plugin, Primitive, ReturnValue, ShellError, Spanned, Value, +}; + +struct NewSkip { + skip_amount: i64, +} +impl NewSkip { + fn new() -> NewSkip { + NewSkip { skip_amount: 0 } + } +} + +impl Plugin for NewSkip { + fn config(&mut self) -> Result { + Ok(CommandConfig { + name: "skip".to_string(), + mandatory_positional: vec![], + optional_positional: vec![], + can_load: vec![], + can_save: vec![], + is_filter: true, + is_sink: false, + named: IndexMap::new(), + rest_positional: true, + }) + } + fn begin_filter(&mut self, args: Args) -> Result<(), ShellError> { + if let Some(args) = args.positional { + for arg in args { + match arg { + Spanned { + item: Value::Primitive(Primitive::Int(i)), + .. + } => { + self.skip_amount = i; + } + _ => return Err(ShellError::string("Unrecognized type in params")), + } + } + } + + Ok(()) + } + + fn filter(&mut self, input: Value) -> Result, ShellError> { + if self.skip_amount == 0 { + Ok(vec![ReturnValue::Value(input)]) + } else { + self.skip_amount -= 1; + Ok(vec![]) + } + } +} + +fn main() { + serve_plugin(&mut NewSkip::new()); +} diff --git a/src/plugins/sum.rs b/src/plugins/sum.rs index 4576ad1d52..f8ac4607a6 100644 --- a/src/plugins/sum.rs +++ b/src/plugins/sum.rs @@ -1,4 +1,5 @@ -use nu::{serve_plugin, Args, Plugin, Primitive, Value}; +use indexmap::IndexMap; +use nu::{serve_plugin, Args, CommandConfig, Plugin, Primitive, ShellError, Value}; struct Sum; @@ -9,6 +10,20 @@ impl Sum { } impl Plugin for Sum { + fn config(&mut self) -> Result { + Ok(CommandConfig { + name: "sum".to_string(), + mandatory_positional: vec![], + optional_positional: vec![], + can_load: vec![], + can_save: vec![], + is_filter: false, + is_sink: true, + named: IndexMap::new(), + rest_positional: true, + }) + } + fn sink(&mut self, _args: Args, input: Vec) { let mut total = 0i64;