From 512dcf0988dd43f95d7af640627e22f6639d6429 Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Tue, 7 Dec 2021 14:06:34 -0600 Subject: [PATCH] enable `cargo build --features=extra` to build plugins (#448) --- Cargo.lock | 3 + Cargo.toml | 65 ++++++++++- crates/nu_plugin_example/src/example.rs | 94 +++++++++++++++ crates/nu_plugin_example/src/lib.rs | 4 + crates/nu_plugin_example/src/main.rs | 146 +----------------------- crates/nu_plugin_example/src/nu/mod.rs | 59 ++++++++++ crates/nu_plugin_gstat/src/nu/mod.rs | 5 +- src/plugins/nu_plugin_core_example.rs | 6 + src/plugins/nu_plugin_core_inc.rs | 6 + src/plugins/nu_plugin_extra_gstat.rs | 6 + 10 files changed, 244 insertions(+), 150 deletions(-) create mode 100644 crates/nu_plugin_example/src/example.rs create mode 100644 crates/nu_plugin_example/src/lib.rs create mode 100644 crates/nu_plugin_example/src/nu/mod.rs create mode 100644 src/plugins/nu_plugin_core_example.rs create mode 100644 src/plugins/nu_plugin_core_inc.rs create mode 100644 src/plugins/nu_plugin_extra_gstat.rs diff --git a/Cargo.lock b/Cargo.lock index b84e4b7a6..2fe88514f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -748,6 +748,9 @@ dependencies = [ "nu-protocol", "nu-table", "nu-term-grid", + "nu_plugin_example", + "nu_plugin_gstat", + "nu_plugin_inc", "pretty_assertions", "reedline", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 7d0b3cf43..903b369de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,12 +38,69 @@ ctrlc = "3.2.1" crossterm_winapi = "0.9.0" # mimalloc = { version = "*", default-features = false } -[features] -plugin = ["nu-plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"] -dataframe = ["nu-command/dataframe"] -default = ["plugin"] + +nu_plugin_inc = { version = "0.1.0", path = "./crates/nu_plugin_inc", optional = true } +nu_plugin_example = { version = "0.1.0", path = "./crates/nu_plugin_example", optional = true } +nu_plugin_gstat = { version = "0.1.0", path = "./crates/nu_plugin_gstat", optional = true } + [dev-dependencies] tempfile = "3.2.0" assert_cmd = "1.0.7" pretty_assertions = "0.7.2" + +[build-dependencies] + +[features] +plugin = ["nu-plugin", "nu-parser/plugin", "nu-command/plugin", "nu-protocol/plugin", "nu-engine/plugin"] + +default = [ + "plugin", + "inc", + "example", + ] + +stable = ["default"] + +extra = [ + "default", + "dataframe", + "gstat", +] + +wasi = ["inc"] + +# Stable (Default) +inc = ["nu_plugin_inc"] +example = ["nu_plugin_example"] + +# Extra +gstat = ["nu_plugin_gstat"] + +# Dataframe feature for nushell +dataframe = ["nu-command/dataframe"] + +[profile.release] +opt-level = "s" # Optimize for size + +# Build plugins +[[bin]] +name = "nu_plugin_inc" +path = "src/plugins/nu_plugin_core_inc.rs" +required-features = ["inc"] + +[[bin]] +name = "nu_plugin_example" +path = "src/plugins/nu_plugin_core_example.rs" +required-features = ["example"] + +# Extra plugins +[[bin]] +name = "nu_plugin_gstat" +path = "src/plugins/nu_plugin_extra_gstat.rs" +required-features = ["gstat"] + +# Main nu binary +[[bin]] +name = "engine-q" +path = "src/main.rs" \ No newline at end of file diff --git a/crates/nu_plugin_example/src/example.rs b/crates/nu_plugin_example/src/example.rs new file mode 100644 index 000000000..856f04b70 --- /dev/null +++ b/crates/nu_plugin_example/src/example.rs @@ -0,0 +1,94 @@ +use nu_plugin::{EvaluatedCall, LabeledError}; +use nu_protocol::Value; +pub struct Example; + +impl Example { + fn print_values( + &self, + index: u32, + call: &EvaluatedCall, + input: &Value, + ) -> Result<(), LabeledError> { + // Note. When debugging your plugin, you may want to print something to the console + // Use the eprintln macro to print your messages. Trying to print to stdout will + // cause a decoding error for your message + eprintln!("Calling test {} signature", index); + eprintln!("value received {:?}", input); + + // To extract the arguments from the Call object you can use the functions req, has_flag, + // opt, rest, and get_flag + // + // Note that plugin calls only accept simple arguments, this means that you can + // pass to the plug in Int and String. This should be improved when the plugin has + // the ability to call back to NuShell to extract more information + // Keep this in mind when designing your plugin signatures + let a: i64 = call.req(0)?; + let b: String = call.req(1)?; + let flag = call.has_flag("flag"); + let opt: Option = call.opt(2)?; + let named: Option = call.get_flag("named")?; + let rest: Vec = call.rest(3)?; + + eprintln!("Required values"); + eprintln!("a: {:}", a); + eprintln!("b: {:}", b); + eprintln!("flag: {:}", flag); + eprintln!("rest: {:?}", rest); + + match opt { + Some(v) => eprintln!("Found optional value opt: {:}", v), + None => eprintln!("No optional value found"), + } + + match named { + Some(v) => eprintln!("Named value: {:?}", v), + None => eprintln!("No named value found"), + } + + Ok(()) + } + + pub fn test1(&self, call: &EvaluatedCall, input: &Value) -> Result { + self.print_values(1, call, input)?; + + Ok(Value::Nothing { span: call.head }) + } + + pub fn test2(&self, call: &EvaluatedCall, input: &Value) -> Result { + self.print_values(2, call, input)?; + + let cols = vec!["one".to_string(), "two".to_string(), "three".to_string()]; + + let vals = (0..10i64) + .map(|i| { + let vals = (0..3) + .map(|v| Value::Int { + val: v * i, + span: call.head, + }) + .collect::>(); + + Value::Record { + cols: cols.clone(), + vals, + span: call.head, + } + }) + .collect::>(); + + Ok(Value::List { + vals, + span: call.head, + }) + } + + pub fn test3(&self, call: &EvaluatedCall, input: &Value) -> Result { + self.print_values(3, call, input)?; + + Err(LabeledError { + label: "ERROR from plugin".into(), + msg: "error message pointing to call head span".into(), + span: Some(call.head), + }) + } +} diff --git a/crates/nu_plugin_example/src/lib.rs b/crates/nu_plugin_example/src/lib.rs new file mode 100644 index 000000000..995d09e8e --- /dev/null +++ b/crates/nu_plugin_example/src/lib.rs @@ -0,0 +1,4 @@ +mod example; +mod nu; + +pub use example::Example; diff --git a/crates/nu_plugin_example/src/main.rs b/crates/nu_plugin_example/src/main.rs index 0259d619a..96c365bef 100644 --- a/crates/nu_plugin_example/src/main.rs +++ b/crates/nu_plugin_example/src/main.rs @@ -1,148 +1,6 @@ -use nu_plugin::{serve_plugin, EvaluatedCall, LabeledError, Plugin}; -use nu_protocol::{Category, Signature, SyntaxShape, Value}; +use nu_plugin::serve_plugin; +use nu_plugin_example::Example; fn main() { serve_plugin(&mut Example {}) } - -struct Example {} - -impl Plugin for Example { - fn signature(&self) -> Vec { - // It is possible to declare multiple signature in a plugin - // Each signature will be converted to a command declaration once the - // plugin is registered to nushell - vec![ - Signature::build("test-1") - .desc("Signature test 1 for plugin. Returns Value::Nothing") - .required("a", SyntaxShape::Int, "required integer value") - .required("b", SyntaxShape::String, "required string value") - .switch("flag", "a flag for the signature", Some('f')) - .optional("opt", SyntaxShape::Int, "Optional number") - .named("named", SyntaxShape::String, "named string", Some('n')) - .rest("rest", SyntaxShape::String, "rest value string") - .category(Category::Experimental), - Signature::build("test-2") - .desc("Signature test 2 for plugin. Returns list of records") - .required("a", SyntaxShape::Int, "required integer value") - .required("b", SyntaxShape::String, "required string value") - .switch("flag", "a flag for the signature", Some('f')) - .optional("opt", SyntaxShape::Int, "Optional number") - .named("named", SyntaxShape::String, "named string", Some('n')) - .rest("rest", SyntaxShape::String, "rest value string") - .category(Category::Experimental), - Signature::build("test-3") - .desc("Signature test 3 for plugin. Returns labeled error") - .required("a", SyntaxShape::Int, "required integer value") - .required("b", SyntaxShape::String, "required string value") - .switch("flag", "a flag for the signature", Some('f')) - .optional("opt", SyntaxShape::Int, "Optional number") - .named("named", SyntaxShape::String, "named string", Some('n')) - .rest("rest", SyntaxShape::String, "rest value string") - .category(Category::Experimental), - ] - } - - fn run( - &mut self, - name: &str, - call: &EvaluatedCall, - input: &Value, - ) -> Result { - // You can use the name to identify what plugin signature was called - match name { - "test-1" => test1(call, input), - "test-2" => test2(call, input), - "test-3" => test3(call, input), - _ => Err(LabeledError { - label: "Plugin call with wrong name signature".into(), - msg: "using the wrong signature".into(), - span: Some(call.head), - }), - } - } -} - -fn print_values(index: u32, call: &EvaluatedCall, input: &Value) -> Result<(), LabeledError> { - // Note. When debugging your plugin, you may want to print something to the console - // Use the eprintln macro to print your messages. Trying to print to stdout will - // cause a decoding error for your message - eprintln!("Calling test {} signature", index); - eprintln!("value received {:?}", input); - - // To extract the arguments from the Call object you can use the functions req, has_flag, - // opt, rest, and get_flag - // - // Note that plugin calls only accept simple arguments, this means that you can - // pass to the plug in Int and String. This should be improved when the plugin has - // the ability to call back to NuShell to extract more information - // Keep this in mind when designing your plugin signatures - let a: i64 = call.req(0)?; - let b: String = call.req(1)?; - let flag = call.has_flag("flag"); - let opt: Option = call.opt(2)?; - let named: Option = call.get_flag("named")?; - let rest: Vec = call.rest(3)?; - - eprintln!("Required values"); - eprintln!("a: {:}", a); - eprintln!("b: {:}", b); - eprintln!("flag: {:}", flag); - eprintln!("rest: {:?}", rest); - - match opt { - Some(v) => eprintln!("Found optional value opt: {:}", v), - None => eprintln!("No optional value found"), - } - - match named { - Some(v) => eprintln!("Named value: {:?}", v), - None => eprintln!("No named value found"), - } - - Ok(()) -} - -fn test1(call: &EvaluatedCall, input: &Value) -> Result { - print_values(1, call, input)?; - - Ok(Value::Nothing { span: call.head }) -} - -fn test2(call: &EvaluatedCall, input: &Value) -> Result { - print_values(2, call, input)?; - - let cols = vec!["one".to_string(), "two".to_string(), "three".to_string()]; - - let vals = (0..10i64) - .map(|i| { - let vals = (0..3) - .map(|v| Value::Int { - val: v * i, - span: call.head, - }) - .collect::>(); - - Value::Record { - cols: cols.clone(), - vals, - span: call.head, - } - }) - .collect::>(); - - Ok(Value::List { - vals, - span: call.head, - }) -} - -fn test3(call: &EvaluatedCall, input: &Value) -> Result { - print_values(3, call, input)?; - - Err(LabeledError { - label: "ERROR from plugin".into(), - msg: "error message pointing to call head span".into(), - span: Some(call.head), - }) -} diff --git a/crates/nu_plugin_example/src/nu/mod.rs b/crates/nu_plugin_example/src/nu/mod.rs new file mode 100644 index 000000000..cd40e698c --- /dev/null +++ b/crates/nu_plugin_example/src/nu/mod.rs @@ -0,0 +1,59 @@ +use crate::Example; +use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; +use nu_protocol::{Category, Signature, SyntaxShape, Value}; + +impl Plugin for Example { + fn signature(&self) -> Vec { + // It is possible to declare multiple signature in a plugin + // Each signature will be converted to a command declaration once the + // plugin is registered to nushell + vec![ + Signature::build("test-1") + .desc("Signature test 1 for plugin. Returns Value::Nothing") + .required("a", SyntaxShape::Int, "required integer value") + .required("b", SyntaxShape::String, "required string value") + .switch("flag", "a flag for the signature", Some('f')) + .optional("opt", SyntaxShape::Int, "Optional number") + .named("named", SyntaxShape::String, "named string", Some('n')) + .rest("rest", SyntaxShape::String, "rest value string") + .category(Category::Experimental), + Signature::build("test-2") + .desc("Signature test 2 for plugin. Returns list of records") + .required("a", SyntaxShape::Int, "required integer value") + .required("b", SyntaxShape::String, "required string value") + .switch("flag", "a flag for the signature", Some('f')) + .optional("opt", SyntaxShape::Int, "Optional number") + .named("named", SyntaxShape::String, "named string", Some('n')) + .rest("rest", SyntaxShape::String, "rest value string") + .category(Category::Experimental), + Signature::build("test-3") + .desc("Signature test 3 for plugin. Returns labeled error") + .required("a", SyntaxShape::Int, "required integer value") + .required("b", SyntaxShape::String, "required string value") + .switch("flag", "a flag for the signature", Some('f')) + .optional("opt", SyntaxShape::Int, "Optional number") + .named("named", SyntaxShape::String, "named string", Some('n')) + .rest("rest", SyntaxShape::String, "rest value string") + .category(Category::Experimental), + ] + } + + fn run( + &mut self, + name: &str, + call: &EvaluatedCall, + input: &Value, + ) -> Result { + // You can use the name to identify what plugin signature was called + match name { + "test-1" => self.test1(call, input), + "test-2" => self.test2(call, input), + "test-3" => self.test3(call, input), + _ => Err(LabeledError { + label: "Plugin call with wrong name signature".into(), + msg: "using the wrong signature".into(), + span: Some(call.head), + }), + } + } +} diff --git a/crates/nu_plugin_gstat/src/nu/mod.rs b/crates/nu_plugin_gstat/src/nu/mod.rs index a89f9c32d..71623f587 100644 --- a/crates/nu_plugin_gstat/src/nu/mod.rs +++ b/crates/nu_plugin_gstat/src/nu/mod.rs @@ -1,12 +1,13 @@ use crate::GStat; use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; -use nu_protocol::{Signature, Span, Spanned, SyntaxShape, Value}; +use nu_protocol::{Category, Signature, Span, Spanned, SyntaxShape, Value}; impl Plugin for GStat { fn signature(&self) -> Vec { vec![Signature::build("gstat") .desc("Get the git status of a repo") - .optional("path", SyntaxShape::String, "path to repo")] + .optional("path", SyntaxShape::String, "path to repo") + .category(Category::Custom("Prompt".to_string()))] } fn run( diff --git a/src/plugins/nu_plugin_core_example.rs b/src/plugins/nu_plugin_core_example.rs new file mode 100644 index 000000000..96c365bef --- /dev/null +++ b/src/plugins/nu_plugin_core_example.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_example::Example; + +fn main() { + serve_plugin(&mut Example {}) +} diff --git a/src/plugins/nu_plugin_core_inc.rs b/src/plugins/nu_plugin_core_inc.rs new file mode 100644 index 000000000..7245f1fbc --- /dev/null +++ b/src/plugins/nu_plugin_core_inc.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_inc::Inc; + +fn main() { + serve_plugin(&mut Inc::new()) +} diff --git a/src/plugins/nu_plugin_extra_gstat.rs b/src/plugins/nu_plugin_extra_gstat.rs new file mode 100644 index 000000000..b15aeefde --- /dev/null +++ b/src/plugins/nu_plugin_extra_gstat.rs @@ -0,0 +1,6 @@ +use nu_plugin::serve_plugin; +use nu_plugin_gstat::GStat; + +fn main() { + serve_plugin(&mut GStat::new()) +}