From e193bf43fb14048ae280b48f5787b5eec21faf5e Mon Sep 17 00:00:00 2001 From: Fernando Herrera Date: Tue, 2 Nov 2021 21:51:11 +0000 Subject: [PATCH] multiple functions in plugin --- crates/nu-parser/src/parse_keywords.rs | 13 +++-- crates/nu-plugin/schema/plugin.capnp | 7 +-- crates/nu-plugin/src/plugin.rs | 20 +++---- crates/nu-plugin/src/plugin_call.rs | 58 ++++++++++++++------ crates/nu-plugin/src/plugin_capnp.rs | 74 +++++++++++++++++++------- 5 files changed, 119 insertions(+), 53 deletions(-) diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index f3df2f2528..30c9092c78 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -963,11 +963,14 @@ pub fn parse_plugin( // get signature from plugin match get_signature(source_file) { Err(err) => Some(ParseError::PluginError(format!("{}", err))), - Ok(signature) => { - // create plugin command declaration (need struct impl Command) - // store declaration in working set - let plugin_decl = PluginDeclaration::new(filename, signature); - working_set.add_decl(Box::new(plugin_decl)); + Ok(signatures) => { + for signature in signatures { + // create plugin command declaration (need struct impl Command) + // store declaration in working set + let plugin_decl = + PluginDeclaration::new(filename.clone(), signature); + working_set.add_decl(Box::new(plugin_decl)); + } None } diff --git a/crates/nu-plugin/schema/plugin.capnp b/crates/nu-plugin/schema/plugin.capnp index 8992bc0f99..ed47822602 100644 --- a/crates/nu-plugin/schema/plugin.capnp +++ b/crates/nu-plugin/schema/plugin.capnp @@ -111,8 +111,9 @@ struct Call { } struct CallInfo { - call @0: Call; - input @1: Value; + name @0: Text; + call @1: Call; + input @2: Value; } # Main communication structs with the plugin @@ -126,7 +127,7 @@ struct PluginCall { struct PluginResponse { union { error @0 :Text; - signature @1 :Signature; + signature @1 :List(Signature); value @2 :Value; } } diff --git a/crates/nu-plugin/src/plugin.rs b/crates/nu-plugin/src/plugin.rs index f83eedd544..b6d3960a1c 100644 --- a/crates/nu-plugin/src/plugin.rs +++ b/crates/nu-plugin/src/plugin.rs @@ -11,6 +11,7 @@ const OUTPUT_BUFFER_SIZE: usize = 8192; #[derive(Debug)] pub struct CallInfo { + pub name: String, pub call: Call, pub input: Value, } @@ -26,7 +27,7 @@ pub enum PluginCall { #[derive(Debug)] pub enum PluginResponse { Error(String), - Signature(Box), + Signature(Vec), Value(Box), } @@ -57,7 +58,7 @@ impl Display for PluginError { } } -pub fn get_signature(path: &Path) -> Result, PluginError> { +pub fn get_signature(path: &Path) -> Result, PluginError> { let mut plugin_cmd = create_command(path); // Both stdout and stdin are piped so we can get the information from the plugin @@ -114,12 +115,12 @@ fn create_command(path: &Path) -> CommandSys { #[derive(Debug, Clone)] pub struct PluginDeclaration { name: String, - signature: Box, + signature: Signature, filename: String, } impl PluginDeclaration { - pub fn new(filename: String, signature: Box) -> Self { + pub fn new(filename: String, signature: Signature) -> Self { Self { name: signature.name.clone(), signature, @@ -134,7 +135,7 @@ impl Command for PluginDeclaration { } fn signature(&self) -> Signature { - self.signature.as_ref().clone() + self.signature.clone() } fn usage(&self) -> &str { @@ -175,6 +176,7 @@ impl Command for PluginDeclaration { // PluginCall information let plugin_call = PluginCall::CallInfo(Box::new(CallInfo { + name: self.name.clone(), call: call.clone(), input, })); @@ -221,8 +223,8 @@ impl Command for PluginDeclaration { /// The `Plugin` trait defines the API which plugins use to "hook" into nushell. pub trait Plugin { - fn signature(&self) -> Signature; - fn run(&self, call: &Call, input: &Value) -> Result; + fn signature(&self) -> Vec; + fn run(&self, name: &str, call: &Call, input: &Value) -> Result; } // Function used in the plugin definition for the communication protocol between @@ -242,12 +244,12 @@ pub fn serve_plugin(plugin: &mut impl Plugin) { match plugin_call { // Sending the signature back to nushell to create the declaration definition PluginCall::Signature => { - let response = PluginResponse::Signature(Box::new(plugin.signature())); + let response = PluginResponse::Signature(plugin.signature()); encode_response(&response, &mut std::io::stdout()) .expect("Error encoding response"); } PluginCall::CallInfo(call_info) => { - let value = plugin.run(&call_info.call, &call_info.input); + let value = plugin.run(&call_info.name, &call_info.call, &call_info.input); let response = match value { Ok(value) => PluginResponse::Value(Box::new(value)), diff --git a/crates/nu-plugin/src/plugin_call.rs b/crates/nu-plugin/src/plugin_call.rs index 40c6c295e1..19e0c73d69 100644 --- a/crates/nu-plugin/src/plugin_call.rs +++ b/crates/nu-plugin/src/plugin_call.rs @@ -1,7 +1,9 @@ use crate::plugin::{CallInfo, PluginCall, PluginError, PluginResponse}; use crate::plugin_capnp::{plugin_call, plugin_response}; +use crate::serializers::signature::deserialize_signature; use crate::serializers::{call, signature, value}; use capnp::serialize_packed; +use nu_protocol::Signature; pub fn encode_call( plugin_call: &PluginCall, @@ -16,6 +18,9 @@ pub fn encode_call( PluginCall::CallInfo(call_info) => { let mut call_info_builder = builder.reborrow().init_call_info(); + // Serializing name from the call + call_info_builder.set_name(call_info.name.as_str()); + // Serializing argument information from the call let call_builder = call_info_builder .reborrow() @@ -53,6 +58,10 @@ pub fn decode_call(reader: &mut impl std::io::BufRead) -> Result { let reader = reader.map_err(|e| PluginError::DecodingError(e.to_string()))?; + let name = reader + .get_name() + .map_err(|e| PluginError::DecodingError(e.to_string()))?; + let call_reader = reader .get_call() .map_err(|e| PluginError::DecodingError(e.to_string()))?; @@ -67,7 +76,11 @@ pub fn decode_call(reader: &mut impl std::io::BufRead) -> Result builder.reborrow().set_error(msg.as_str()), - PluginResponse::Signature(sign) => { - let signature_builder = builder.reborrow().init_signature(); - signature::serialize_signature(sign, signature_builder) + PluginResponse::Signature(signatures) => { + let mut signature_list_builder = + builder.reborrow().init_signature(signatures.len() as u32); + + for (index, signature) in signatures.iter().enumerate() { + let signature_builder = signature_list_builder.reborrow().get(index as u32); + signature::serialize_signature(signature, signature_builder) + } } PluginResponse::Value(val) => { let value_builder = builder.reborrow().init_value(); @@ -113,10 +131,13 @@ pub fn decode_response(reader: &mut impl std::io::BufRead) -> Result { let reader = reader.map_err(|e| PluginError::DecodingError(e.to_string()))?; - let sign = signature::deserialize_signature(reader) - .map_err(|e| PluginError::DecodingError(e.to_string()))?; - Ok(PluginResponse::Signature(Box::new(sign))) + let signatures = reader + .iter() + .map(deserialize_signature) + .collect::, PluginError>>()?; + + Ok(PluginResponse::Signature(signatures)) } Ok(plugin_response::Value(reader)) => { let reader = reader.map_err(|e| PluginError::DecodingError(e.to_string()))?; @@ -163,6 +184,8 @@ mod tests { #[test] fn callinfo_round_trip_callinfo() { + let name = "test".to_string(); + let input = Value::Bool { val: false, span: Span { start: 1, end: 20 }, @@ -200,6 +223,7 @@ mod tests { }; let plugin_call = PluginCall::CallInfo(Box::new(CallInfo { + name: name.clone(), call: call.clone(), input: input.clone(), })); @@ -211,6 +235,7 @@ mod tests { match returned { PluginCall::Signature => panic!("returned wrong call type"), PluginCall::CallInfo(call_info) => { + assert_eq!(name, call_info.name); assert_eq!(input, call_info.input); assert_eq!(call.head, call_info.call.head); assert_eq!(call.positional.len(), call_info.call.positional.len()); @@ -251,7 +276,7 @@ mod tests { ) .rest("remaining", SyntaxShape::Int, "remaining"); - let response = PluginResponse::Signature(Box::new(signature.clone())); + let response = PluginResponse::Signature(vec![signature.clone()]); let mut buffer: Vec = Vec::new(); encode_response(&response, &mut buffer).expect("unable to serialize message"); @@ -262,32 +287,33 @@ mod tests { PluginResponse::Error(_) => panic!("returned wrong call type"), PluginResponse::Value(_) => panic!("returned wrong call type"), PluginResponse::Signature(returned_signature) => { - assert_eq!(signature.name, returned_signature.name); - assert_eq!(signature.usage, returned_signature.usage); - assert_eq!(signature.extra_usage, returned_signature.extra_usage); - assert_eq!(signature.is_filter, returned_signature.is_filter); + assert!(returned_signature.len() == 1); + assert_eq!(signature.name, returned_signature[0].name); + assert_eq!(signature.usage, returned_signature[0].usage); + assert_eq!(signature.extra_usage, returned_signature[0].extra_usage); + assert_eq!(signature.is_filter, returned_signature[0].is_filter); signature .required_positional .iter() - .zip(returned_signature.required_positional.iter()) + .zip(returned_signature[0].required_positional.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); signature .optional_positional .iter() - .zip(returned_signature.optional_positional.iter()) + .zip(returned_signature[0].optional_positional.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); signature .named .iter() - .zip(returned_signature.named.iter()) + .zip(returned_signature[0].named.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); assert_eq!( signature.rest_positional, - returned_signature.rest_positional, + returned_signature[0].rest_positional, ); } } diff --git a/crates/nu-plugin/src/plugin_capnp.rs b/crates/nu-plugin/src/plugin_capnp.rs index cd49bad6e0..4aca078fb7 100644 --- a/crates/nu-plugin/src/plugin_capnp.rs +++ b/crates/nu-plugin/src/plugin_capnp.rs @@ -3480,25 +3480,35 @@ pub mod call_info { self.reader.total_size() } #[inline] - pub fn get_call(self) -> ::capnp::Result> { + pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> { ::capnp::traits::FromPointerReader::get_from_pointer( &self.reader.get_pointer_field(0), ::core::option::Option::None, ) } - pub fn has_call(&self) -> bool { + pub fn has_name(&self) -> bool { !self.reader.get_pointer_field(0).is_null() } #[inline] - pub fn get_input(self) -> ::capnp::Result> { + pub fn get_call(self) -> ::capnp::Result> { ::capnp::traits::FromPointerReader::get_from_pointer( &self.reader.get_pointer_field(1), ::core::option::Option::None, ) } - pub fn has_input(&self) -> bool { + pub fn has_call(&self) -> bool { !self.reader.get_pointer_field(1).is_null() } + #[inline] + pub fn get_input(self) -> ::capnp::Result> { + ::capnp::traits::FromPointerReader::get_from_pointer( + &self.reader.get_pointer_field(2), + ::core::option::Option::None, + ) + } + pub fn has_input(&self) -> bool { + !self.reader.get_pointer_field(2).is_null() + } } pub struct Builder<'a> { @@ -3571,34 +3581,52 @@ pub mod call_info { self.builder.into_reader().total_size() } #[inline] - pub fn get_call(self) -> ::capnp::Result> { + pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> { ::capnp::traits::FromPointerBuilder::get_from_pointer( self.builder.get_pointer_field(0), ::core::option::Option::None, ) } #[inline] + pub fn set_name(&mut self, value: ::capnp::text::Reader<'_>) { + self.builder.get_pointer_field(0).set_text(value); + } + #[inline] + pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> { + self.builder.get_pointer_field(0).init_text(size) + } + pub fn has_name(&self) -> bool { + !self.builder.get_pointer_field(0).is_null() + } + #[inline] + pub fn get_call(self) -> ::capnp::Result> { + ::capnp::traits::FromPointerBuilder::get_from_pointer( + self.builder.get_pointer_field(1), + ::core::option::Option::None, + ) + } + #[inline] pub fn set_call( &mut self, value: crate::plugin_capnp::call::Reader<'_>, ) -> ::capnp::Result<()> { ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.get_pointer_field(0), + self.builder.get_pointer_field(1), value, false, ) } #[inline] pub fn init_call(self) -> crate::plugin_capnp::call::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), 0) + ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(1), 0) } pub fn has_call(&self) -> bool { - !self.builder.get_pointer_field(0).is_null() + !self.builder.get_pointer_field(1).is_null() } #[inline] pub fn get_input(self) -> ::capnp::Result> { ::capnp::traits::FromPointerBuilder::get_from_pointer( - self.builder.get_pointer_field(1), + self.builder.get_pointer_field(2), ::core::option::Option::None, ) } @@ -3608,17 +3636,17 @@ pub mod call_info { value: crate::plugin_capnp::value::Reader<'_>, ) -> ::capnp::Result<()> { ::capnp::traits::SetPointerBuilder::set_pointer_builder( - self.builder.get_pointer_field(1), + self.builder.get_pointer_field(2), value, false, ) } #[inline] pub fn init_input(self) -> crate::plugin_capnp::value::Builder<'a> { - ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(1), 0) + ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(2), 0) } pub fn has_input(&self) -> bool { - !self.builder.get_pointer_field(1).is_null() + !self.builder.get_pointer_field(2).is_null() } } @@ -3634,17 +3662,17 @@ pub mod call_info { } impl Pipeline { pub fn get_call(&self) -> crate::plugin_capnp::call::Pipeline { - ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(0)) + ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(1)) } pub fn get_input(&self) -> crate::plugin_capnp::value::Pipeline { - ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(1)) + ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(2)) } } mod _private { use capnp::private::layout; pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, - pointers: 2, + pointers: 3, }; pub const TYPE_ID: u64 = 0x8e03_127e_9170_7d6a; } @@ -4073,7 +4101,7 @@ pub mod plugin_response { #[inline] pub fn set_signature( &mut self, - value: crate::plugin_capnp::signature::Reader<'_>, + value: ::capnp::struct_list::Reader<'a, crate::plugin_capnp::signature::Owned>, ) -> ::capnp::Result<()> { self.builder.set_data_field::(0, 1); ::capnp::traits::SetPointerBuilder::set_pointer_builder( @@ -4083,9 +4111,15 @@ pub mod plugin_response { ) } #[inline] - pub fn init_signature(self) -> crate::plugin_capnp::signature::Builder<'a> { + pub fn init_signature( + self, + size: u32, + ) -> ::capnp::struct_list::Builder<'a, crate::plugin_capnp::signature::Owned> { self.builder.set_data_field::(0, 1); - ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), 0) + ::capnp::traits::FromPointerBuilder::init_pointer( + self.builder.get_pointer_field(0), + size, + ) } pub fn has_signature(&self) -> bool { if self.builder.get_data_field::(0) != 1 { @@ -4168,12 +4202,12 @@ pub mod plugin_response { } pub type WhichReader<'a> = Which< ::capnp::Result<::capnp::text::Reader<'a>>, - ::capnp::Result>, + ::capnp::Result<::capnp::struct_list::Reader<'a, crate::plugin_capnp::signature::Owned>>, ::capnp::Result>, >; pub type WhichBuilder<'a> = Which< ::capnp::Result<::capnp::text::Builder<'a>>, - ::capnp::Result>, + ::capnp::Result<::capnp::struct_list::Builder<'a, crate::plugin_capnp::signature::Owned>>, ::capnp::Result>, >; }