forked from extern/nushell
multiple functions in plugin
This commit is contained in:
parent
12eed1f98a
commit
e193bf43fb
@ -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) => {
|
||||
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, signature);
|
||||
let plugin_decl =
|
||||
PluginDeclaration::new(filename.clone(), signature);
|
||||
working_set.add_decl(Box::new(plugin_decl));
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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>),
|
||||
Signature(Vec<Signature>),
|
||||
Value(Box<Value>),
|
||||
}
|
||||
|
||||
@ -57,7 +58,7 @@ impl Display for PluginError {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_signature(path: &Path) -> Result<Box<Signature>, PluginError> {
|
||||
pub fn get_signature(path: &Path) -> Result<Vec<Signature>, 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: Signature,
|
||||
filename: String,
|
||||
}
|
||||
|
||||
impl PluginDeclaration {
|
||||
pub fn new(filename: String, signature: Box<Signature>) -> 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<Value, PluginError>;
|
||||
fn signature(&self) -> Vec<Signature>;
|
||||
fn run(&self, name: &str, call: &Call, input: &Value) -> Result<Value, PluginError>;
|
||||
}
|
||||
|
||||
// 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)),
|
||||
|
@ -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<PluginCall, Plu
|
||||
Ok(plugin_call::CallInfo(reader)) => {
|
||||
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<PluginCall, Plu
|
||||
let input = value::deserialize_value(input_reader)
|
||||
.map_err(|e| PluginError::DecodingError(e.to_string()))?;
|
||||
|
||||
Ok(PluginCall::CallInfo(Box::new(CallInfo { call, input })))
|
||||
Ok(PluginCall::CallInfo(Box::new(CallInfo {
|
||||
name: name.to_string(),
|
||||
call,
|
||||
input,
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,9 +95,14 @@ pub fn encode_response(
|
||||
|
||||
match &plugin_response {
|
||||
PluginResponse::Error(msg) => 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<PluginRespo
|
||||
}
|
||||
Ok(plugin_response::Signature(reader)) => {
|
||||
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::<Result<Vec<Signature>, 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<u8> = 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3480,25 +3480,35 @@ pub mod call_info {
|
||||
self.reader.total_size()
|
||||
}
|
||||
#[inline]
|
||||
pub fn get_call(self) -> ::capnp::Result<crate::plugin_capnp::call::Reader<'a>> {
|
||||
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<crate::plugin_capnp::value::Reader<'a>> {
|
||||
pub fn get_call(self) -> ::capnp::Result<crate::plugin_capnp::call::Reader<'a>> {
|
||||
::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<crate::plugin_capnp::value::Reader<'a>> {
|
||||
::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<crate::plugin_capnp::call::Builder<'a>> {
|
||||
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<crate::plugin_capnp::call::Builder<'a>> {
|
||||
::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<crate::plugin_capnp::value::Builder<'a>> {
|
||||
::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::<u16>(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::<u16>(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::<u16>(0) != 1 {
|
||||
@ -4168,12 +4202,12 @@ pub mod plugin_response {
|
||||
}
|
||||
pub type WhichReader<'a> = Which<
|
||||
::capnp::Result<::capnp::text::Reader<'a>>,
|
||||
::capnp::Result<crate::plugin_capnp::signature::Reader<'a>>,
|
||||
::capnp::Result<::capnp::struct_list::Reader<'a, crate::plugin_capnp::signature::Owned>>,
|
||||
::capnp::Result<crate::plugin_capnp::value::Reader<'a>>,
|
||||
>;
|
||||
pub type WhichBuilder<'a> = Which<
|
||||
::capnp::Result<::capnp::text::Builder<'a>>,
|
||||
::capnp::Result<crate::plugin_capnp::signature::Builder<'a>>,
|
||||
::capnp::Result<::capnp::struct_list::Builder<'a, crate::plugin_capnp::signature::Owned>>,
|
||||
::capnp::Result<crate::plugin_capnp::value::Builder<'a>>,
|
||||
>;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user