diff --git a/crates/nu-command/src/dataframe/test_dataframe.rs b/crates/nu-command/src/dataframe/test_dataframe.rs index 6b8a9a89c..983e13a00 100644 --- a/crates/nu-command/src/dataframe/test_dataframe.rs +++ b/crates/nu-command/src/dataframe/test_dataframe.rs @@ -30,7 +30,7 @@ pub fn test_dataframe(cmds: Vec>) { working_set.add_decl(Box::new(ExprCol)); // Adding the command that is being tested to the working set - for cmd in cmds { + for cmd in cmds.clone() { working_set.add_decl(cmd); } diff --git a/crates/nu-command/src/formats/from/yaml.rs b/crates/nu-command/src/formats/from/yaml.rs index 43dcc138f..940054604 100644 --- a/crates/nu-command/src/formats/from/yaml.rs +++ b/crates/nu-command/src/formats/from/yaml.rs @@ -208,7 +208,7 @@ pub fn from_yaml_string_to_value( } } -pub fn get_examples() -> Vec { +pub fn get_examples() -> Vec> { vec![ Example { example: "'a: 1' | from yaml", diff --git a/crates/nu-command/src/hash/generic_digest.rs b/crates/nu-command/src/hash/generic_digest.rs index 014770f0a..088aefa63 100644 --- a/crates/nu-command/src/hash/generic_digest.rs +++ b/crates/nu-command/src/hash/generic_digest.rs @@ -8,7 +8,7 @@ use std::marker::PhantomData; pub trait HashDigest: digest::Digest + Clone { fn name() -> &'static str; - fn examples() -> Vec; + fn examples() -> Vec>; } #[derive(Clone)] @@ -70,7 +70,7 @@ where &self.usage } - fn examples(&self) -> Vec { + fn examples(&self) -> Vec> { D::examples() } diff --git a/crates/nu-command/src/hash/md5.rs b/crates/nu-command/src/hash/md5.rs index 7f6635713..0c1238174 100644 --- a/crates/nu-command/src/hash/md5.rs +++ b/crates/nu-command/src/hash/md5.rs @@ -9,7 +9,7 @@ impl HashDigest for Md5 { "md5" } - fn examples() -> Vec { + fn examples() -> Vec> { vec![ Example { description: "Return the md5 hash of a string, hex-encoded", diff --git a/crates/nu-command/src/hash/sha256.rs b/crates/nu-command/src/hash/sha256.rs index bcef4a639..08bebe2db 100644 --- a/crates/nu-command/src/hash/sha256.rs +++ b/crates/nu-command/src/hash/sha256.rs @@ -9,7 +9,7 @@ impl HashDigest for Sha256 { "sha256" } - fn examples() -> Vec { + fn examples() -> Vec> { vec![ Example { description: "Return the sha256 hash of a string, hex-encoded", diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 724d1c920..b37ab9950 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -3475,7 +3475,7 @@ pub fn parse_register( expand_aliases_denylist: &[usize], ) -> (Pipeline, Option) { use nu_plugin::{get_signature, PluginDeclaration}; - use nu_protocol::{engine::Stack, Signature}; + use nu_protocol::{engine::Stack, PluginSignature}; let cwd = working_set.get_cwd(); @@ -3573,7 +3573,7 @@ pub fn parse_register( // the plugin is called to get the signatures or to use the given signature let signature = call.positional_nth(1).map(|expr| { let signature = working_set.get_span_contents(expr.span); - serde_json::from_slice::(signature).map_err(|e| { + serde_json::from_slice::(signature).map_err(|e| { ParseError::LabeledError( "Signature deserialization error".into(), format!("unable to deserialize signature: {e}"), diff --git a/crates/nu-plugin/src/plugin/declaration.rs b/crates/nu-plugin/src/plugin/declaration.rs index d03e3f15d..ab17c4bd7 100644 --- a/crates/nu-plugin/src/plugin/declaration.rs +++ b/crates/nu-plugin/src/plugin/declaration.rs @@ -7,21 +7,21 @@ use crate::protocol::{ use std::path::{Path, PathBuf}; use nu_protocol::engine::{Command, EngineState, Stack}; -use nu_protocol::{ast::Call, Signature}; -use nu_protocol::{PipelineData, ShellError, Value}; +use nu_protocol::{ast::Call, PluginSignature, Signature}; +use nu_protocol::{Example, PipelineData, ShellError, Value}; #[derive(Clone)] pub struct PluginDeclaration { name: String, - signature: Signature, + signature: PluginSignature, filename: PathBuf, shell: Option, } impl PluginDeclaration { - pub fn new(filename: PathBuf, signature: Signature, shell: Option) -> Self { + pub fn new(filename: PathBuf, signature: PluginSignature, shell: Option) -> Self { Self { - name: signature.name.clone(), + name: signature.sig.name.clone(), signature, filename, shell, @@ -35,11 +35,23 @@ impl Command for PluginDeclaration { } fn signature(&self) -> Signature { - self.signature.clone() + self.signature.sig.clone() } fn usage(&self) -> &str { - self.signature.usage.as_str() + self.signature.sig.usage.as_str() + } + + fn examples(&self) -> Vec { + let mut res = vec![]; + for e in self.signature.examples.iter() { + res.push(Example { + example: &e.example, + description: &e.description, + result: e.result.clone(), + }) + } + res } fn run( diff --git a/crates/nu-plugin/src/plugin/mod.rs b/crates/nu-plugin/src/plugin/mod.rs index a747af6ad..f7d206158 100644 --- a/crates/nu-plugin/src/plugin/mod.rs +++ b/crates/nu-plugin/src/plugin/mod.rs @@ -11,8 +11,7 @@ use std::io::{BufReader, ErrorKind, Read, Write as WriteTrait}; use std::path::{Path, PathBuf}; use std::process::{Child, ChildStdout, Command as CommandSys, Stdio}; -use nu_protocol::{CustomValue, ShellError, Span}; -use nu_protocol::{Signature, Value}; +use nu_protocol::{CustomValue, PluginSignature, ShellError, Span, Value}; use super::EvaluatedCall; @@ -118,7 +117,7 @@ pub fn get_signature( path: &Path, shell: &Option, current_envs: &HashMap, -) -> Result, ShellError> { +) -> Result, ShellError> { let mut plugin_cmd = create_command(path, shell); let program_name = plugin_cmd.get_program().to_os_string().into_string(); @@ -183,7 +182,7 @@ pub fn get_signature( // The next trait and functions are part of the plugin that is being created // The `Plugin` trait defines the API which plugins use to "hook" into nushell. pub trait Plugin { - fn signature(&self) -> Vec; + fn signature(&self) -> Vec; fn run( &mut self, name: &str, @@ -311,22 +310,23 @@ fn print_help(plugin: &mut impl Plugin, encoder: impl PluginEncoder) { let mut help = String::new(); plugin.signature().iter().for_each(|signature| { - let res = write!(help, "\nCommand: {}", signature.name) - .and_then(|_| writeln!(help, "\nUsage:\n > {}", signature.usage)) + let res = write!(help, "\nCommand: {}", signature.sig.name) + .and_then(|_| writeln!(help, "\nUsage:\n > {}", signature.sig.usage)) .and_then(|_| { - if !signature.extra_usage.is_empty() { - writeln!(help, "\nExtra usage:\n > {}", signature.extra_usage) + if !signature.sig.extra_usage.is_empty() { + writeln!(help, "\nExtra usage:\n > {}", signature.sig.extra_usage) } else { Ok(()) } }) .and_then(|_| { - let flags = get_flags_section(signature); + let flags = get_flags_section(&signature.sig); write!(help, "{flags}") }) .and_then(|_| writeln!(help, "\nParameters:")) .and_then(|_| { signature + .sig .required_positional .iter() .try_for_each(|positional| { @@ -339,6 +339,7 @@ fn print_help(plugin: &mut impl Plugin, encoder: impl PluginEncoder) { }) .and_then(|_| { signature + .sig .optional_positional .iter() .try_for_each(|positional| { @@ -350,7 +351,7 @@ fn print_help(plugin: &mut impl Plugin, encoder: impl PluginEncoder) { }) }) .and_then(|_| { - if let Some(rest_positional) = &signature.rest_positional { + if let Some(rest_positional) = &signature.sig.rest_positional { writeln!( help, " ...{} <{}>: {}", diff --git a/crates/nu-plugin/src/protocol/mod.rs b/crates/nu-plugin/src/protocol/mod.rs index 78bcee1b7..211865da1 100644 --- a/crates/nu-plugin/src/protocol/mod.rs +++ b/crates/nu-plugin/src/protocol/mod.rs @@ -3,7 +3,7 @@ mod plugin_custom_value; mod plugin_data; pub use evaluated_call::EvaluatedCall; -use nu_protocol::{ShellError, Signature, Span, Value}; +use nu_protocol::{PluginSignature, ShellError, Span, Value}; pub use plugin_custom_value::PluginCustomValue; pub use plugin_data::PluginData; use serde::{Deserialize, Serialize}; @@ -97,7 +97,7 @@ impl From for LabeledError { #[derive(Serialize, Deserialize)] pub enum PluginResponse { Error(LabeledError), - Signature(Vec), + Signature(Vec), Value(Box), PluginData(String, PluginData), } diff --git a/crates/nu-plugin/src/serializers/json.rs b/crates/nu-plugin/src/serializers/json.rs index 2e7916bc6..3a9cd1ac3 100644 --- a/crates/nu-plugin/src/serializers/json.rs +++ b/crates/nu-plugin/src/serializers/json.rs @@ -51,7 +51,7 @@ mod tests { use crate::protocol::{ CallInfo, CallInput, EvaluatedCall, LabeledError, PluginCall, PluginData, PluginResponse, }; - use nu_protocol::{Signature, Span, Spanned, SyntaxShape, Value}; + use nu_protocol::{PluginSignature, Span, Spanned, SyntaxShape, Value}; #[test] fn callinfo_round_trip_signature() { @@ -183,7 +183,7 @@ mod tests { #[test] fn response_round_trip_signature() { - let signature = Signature::build("nu-plugin") + let signature = PluginSignature::build("nu-plugin") .required("first", SyntaxShape::String, "first required") .required("second", SyntaxShape::Int, "second required") .required_named("first-named", SyntaxShape::String, "first named", Some('f')) @@ -212,32 +212,38 @@ mod tests { PluginResponse::PluginData(..) => panic!("returned wrong call type"), PluginResponse::Signature(returned_signature) => { assert_eq!(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); + assert_eq!(signature.sig.name, returned_signature[0].sig.name); + assert_eq!(signature.sig.usage, returned_signature[0].sig.usage); + assert_eq!( + signature.sig.extra_usage, + returned_signature[0].sig.extra_usage + ); + assert_eq!(signature.sig.is_filter, returned_signature[0].sig.is_filter); signature + .sig .required_positional .iter() - .zip(returned_signature[0].required_positional.iter()) + .zip(returned_signature[0].sig.required_positional.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); signature + .sig .optional_positional .iter() - .zip(returned_signature[0].optional_positional.iter()) + .zip(returned_signature[0].sig.optional_positional.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); signature + .sig .named .iter() - .zip(returned_signature[0].named.iter()) + .zip(returned_signature[0].sig.named.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); assert_eq!( - signature.rest_positional, - returned_signature[0].rest_positional, + signature.sig.rest_positional, + returned_signature[0].sig.rest_positional, ); } } diff --git a/crates/nu-plugin/src/serializers/msgpack.rs b/crates/nu-plugin/src/serializers/msgpack.rs index 8f325227d..ff4aa08e0 100644 --- a/crates/nu-plugin/src/serializers/msgpack.rs +++ b/crates/nu-plugin/src/serializers/msgpack.rs @@ -50,7 +50,7 @@ mod tests { use crate::protocol::{ CallInfo, CallInput, EvaluatedCall, LabeledError, PluginCall, PluginData, PluginResponse, }; - use nu_protocol::{Signature, Span, Spanned, SyntaxShape, Value}; + use nu_protocol::{PluginSignature, Span, Spanned, SyntaxShape, Value}; #[test] fn callinfo_round_trip_signature() { @@ -182,7 +182,7 @@ mod tests { #[test] fn response_round_trip_signature() { - let signature = Signature::build("nu-plugin") + let signature = PluginSignature::build("nu-plugin") .required("first", SyntaxShape::String, "first required") .required("second", SyntaxShape::Int, "second required") .required_named("first-named", SyntaxShape::String, "first named", Some('f')) @@ -211,32 +211,38 @@ mod tests { PluginResponse::PluginData(..) => panic!("returned wrong call type"), PluginResponse::Signature(returned_signature) => { assert_eq!(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); + assert_eq!(signature.sig.name, returned_signature[0].sig.name); + assert_eq!(signature.sig.usage, returned_signature[0].sig.usage); + assert_eq!( + signature.sig.extra_usage, + returned_signature[0].sig.extra_usage + ); + assert_eq!(signature.sig.is_filter, returned_signature[0].sig.is_filter); signature + .sig .required_positional .iter() - .zip(returned_signature[0].required_positional.iter()) + .zip(returned_signature[0].sig.required_positional.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); signature + .sig .optional_positional .iter() - .zip(returned_signature[0].optional_positional.iter()) + .zip(returned_signature[0].sig.optional_positional.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); signature + .sig .named .iter() - .zip(returned_signature[0].named.iter()) + .zip(returned_signature[0].sig.named.iter()) .for_each(|(lhs, rhs)| assert_eq!(lhs, rhs)); assert_eq!( - signature.rest_positional, - returned_signature[0].rest_positional, + signature.sig.rest_positional, + returned_signature[0].sig.rest_positional, ); } } diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index fca6df1d6..27a9908c9 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -453,6 +453,8 @@ impl EngineState { pub fn update_plugin_file(&self) -> Result<(), ShellError> { use std::io::Write; + use crate::{PluginExample, PluginSignature}; + // Updating the signatures plugin file with the added signatures self.plugin_signatures .as_ref() @@ -481,7 +483,18 @@ impl EngineState { file_name = format!("`{file_name}`"); } - serde_json::to_string_pretty(&decl.signature()) + let sig = decl.signature(); + let examples = decl + .examples() + .into_iter() + .map(|eg| PluginExample { + example: eg.example.into(), + description: eg.description.into(), + result: eg.result, + }) + .collect(); + let sig_with_examples = PluginSignature::new(sig, examples); + serde_json::to_string_pretty(&sig_with_examples) .map(|signature| { // Extracting the possible path to the shell used to load the plugin let shell_str = shell diff --git a/crates/nu-protocol/src/example.rs b/crates/nu-protocol/src/example.rs index 9d2c0b5e8..c19bb8dab 100644 --- a/crates/nu-protocol/src/example.rs +++ b/crates/nu-protocol/src/example.rs @@ -1,8 +1,20 @@ use crate::Value; +use serde::{Deserialize, Serialize}; #[derive(Debug)] -pub struct Example { - pub example: &'static str, - pub description: &'static str, +pub struct Example<'a> { + pub example: &'a str, + pub description: &'a str, + pub result: Option, +} + +// PluginExample is somehow like struct `Example`, but it owned a String for `example` +// and `description` fields, because these information is fetched from plugin, a third party +// binary, nushell have no way to construct it directly. +#[cfg(feature = "plugin")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PluginExample { + pub example: String, + pub description: String, pub result: Option, } diff --git a/crates/nu-protocol/src/lib.rs b/crates/nu-protocol/src/lib.rs index fff11f5f4..8673c77ee 100644 --- a/crates/nu-protocol/src/lib.rs +++ b/crates/nu-protocol/src/lib.rs @@ -8,6 +8,8 @@ mod id; mod lev_distance; mod module; mod pipeline_data; +#[cfg(feature = "plugin")] +mod plugin_signature; mod shell_error; mod signature; pub mod span; @@ -25,6 +27,8 @@ pub use exportable::*; pub use id::*; pub use module::*; pub use pipeline_data::*; +#[cfg(feature = "plugin")] +pub use plugin_signature::*; pub use shell_error::*; pub use signature::*; pub use span::*; diff --git a/crates/nu-protocol/src/plugin_signature.rs b/crates/nu-protocol/src/plugin_signature.rs new file mode 100644 index 000000000..96e2d2e1d --- /dev/null +++ b/crates/nu-protocol/src/plugin_signature.rs @@ -0,0 +1,246 @@ +use crate::{PluginExample, Signature}; +use serde::Deserialize; +use serde::Serialize; + +use crate::engine::Command; +use crate::{BlockId, Category, Flag, PositionalArg, SyntaxShape, Type}; + +/// A simple wrapper for Signature, includes examples. +#[derive(Clone, Serialize, Deserialize)] +pub struct PluginSignature { + pub sig: Signature, + pub examples: Vec, +} + +impl std::fmt::Display for PluginSignature { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.sig) + } +} + +impl PluginSignature { + pub fn new(sig: Signature, examples: Vec) -> Self { + Self { sig, examples } + } + + // Add a default help option to a signature + pub fn add_help(mut self) -> PluginSignature { + self.sig = self.sig.add_help(); + self + } + + // Build an internal signature with default help option + pub fn build(name: impl Into) -> PluginSignature { + let sig = Signature::new(name.into()).add_help(); + Self::new(sig, vec![]) + } + + /// Add a description to the signature + pub fn usage(mut self, msg: impl Into) -> PluginSignature { + self.sig = self.sig.usage(msg); + self + } + + /// Add an extra description to the signature + pub fn extra_usage(mut self, msg: impl Into) -> PluginSignature { + self.sig = self.sig.extra_usage(msg); + self + } + + /// Add search terms to the signature + pub fn search_terms(mut self, terms: Vec) -> PluginSignature { + self.sig = self.sig.search_terms(terms); + self + } + + /// Update signature's fields from a Command trait implementation + pub fn update_from_command(mut self, name: String, command: &dyn Command) -> PluginSignature { + self.sig = self.sig.update_from_command(name, command); + self + } + + /// Allow unknown signature parameters + pub fn allows_unknown_args(mut self) -> PluginSignature { + self.sig = self.sig.allows_unknown_args(); + self + } + + /// Add a required positional argument to the signature + pub fn required( + mut self, + name: impl Into, + shape: impl Into, + desc: impl Into, + ) -> PluginSignature { + self.sig = self.sig.required(name, shape, desc); + self + } + + /// Add an optional positional argument to the signature + pub fn optional( + mut self, + name: impl Into, + shape: impl Into, + desc: impl Into, + ) -> PluginSignature { + self.sig = self.sig.optional(name, shape, desc); + self + } + + pub fn rest( + mut self, + name: &str, + shape: impl Into, + desc: impl Into, + ) -> PluginSignature { + self.sig = self.sig.rest(name, shape, desc); + + self + } + + /// Is this command capable of operating on its input via cell paths? + pub fn operates_on_cell_paths(&self) -> bool { + self.sig.operates_on_cell_paths() + } + + /// Add an optional named flag argument to the signature + pub fn named( + mut self, + name: impl Into, + shape: impl Into, + desc: impl Into, + short: Option, + ) -> PluginSignature { + self.sig = self.sig.named(name, shape, desc, short); + + self + } + + /// Add a required named flag argument to the signature + pub fn required_named( + mut self, + name: impl Into, + shape: impl Into, + desc: impl Into, + short: Option, + ) -> PluginSignature { + self.sig = self.sig.required_named(name, shape, desc, short); + self + } + + /// Add a switch to the signature + pub fn switch( + mut self, + name: impl Into, + desc: impl Into, + short: Option, + ) -> PluginSignature { + self.sig = self.sig.switch(name, desc, short); + self + } + + /// Changes the input type of the command signature + pub fn input_type(mut self, input_type: Type) -> PluginSignature { + self.sig = self.sig.input_type(input_type); + self + } + + /// Changes the output type of the command signature + pub fn output_type(mut self, output_type: Type) -> PluginSignature { + self.sig = self.sig.output_type(output_type); + self + } + + pub fn vectorizes_over_list(mut self, vectorizes_over_list: bool) -> PluginSignature { + self.sig = self.sig.vectorizes_over_list(vectorizes_over_list); + self + } + + /// Set the input-output type signature variants of the command + pub fn input_output_types(mut self, input_output_types: Vec<(Type, Type)>) -> PluginSignature { + self.sig = self.sig.input_output_types(input_output_types); + self + } + + /// Changes the signature category + pub fn category(mut self, category: Category) -> PluginSignature { + self.sig = self.sig.category(category); + + self + } + + /// Sets that signature will create a scope as it parses + pub fn creates_scope(mut self) -> PluginSignature { + self.sig = self.sig.creates_scope(); + self + } + + // Is it allowed for the type signature to feature a variant that has no corresponding example? + pub fn allow_variants_without_examples(mut self, allow: bool) -> PluginSignature { + self.sig = self.sig.allow_variants_without_examples(allow); + self + } + + pub fn call_signature(&self) -> String { + self.sig.call_signature() + } + + /// Get list of the short-hand flags + pub fn get_shorts(&self) -> Vec { + self.sig.get_shorts() + } + + /// Get list of the long-hand flags + pub fn get_names(&self) -> Vec<&str> { + self.sig.get_names() + } + + pub fn get_positional(&self, position: usize) -> Option { + self.sig.get_positional(position) + } + + pub fn num_positionals(&self) -> usize { + self.sig.num_positionals() + } + + pub fn num_positionals_after(&self, idx: usize) -> usize { + self.sig.num_positionals_after(idx) + } + + /// Find the matching long flag + pub fn get_long_flag(&self, name: &str) -> Option { + self.sig.get_long_flag(name) + } + + /// Find the matching long flag + pub fn get_short_flag(&self, short: char) -> Option { + self.sig.get_short_flag(short) + } + + /// Set the filter flag for the signature + pub fn filter(mut self) -> PluginSignature { + self.sig = self.sig.filter(); + self + } + + /// Create a placeholder implementation of Command as a way to predeclare a definition's + /// signature so other definitions can see it. This placeholder is later replaced with the + /// full definition in a second pass of the parser. + pub fn predeclare(self) -> Box { + self.sig.predeclare() + } + + /// Combines a signature and a block into a runnable block + pub fn into_block_command(self, block_id: BlockId) -> Box { + self.sig.into_block_command(block_id) + } + + pub fn formatted_flags(self) -> String { + self.sig.formatted_flags() + } + + pub fn plugin_examples(mut self, examples: Vec) -> PluginSignature { + self.examples = examples; + self + } +} diff --git a/crates/nu_plugin_custom_values/src/main.rs b/crates/nu_plugin_custom_values/src/main.rs index 112dccca5..0c9c152c5 100644 --- a/crates/nu_plugin_custom_values/src/main.rs +++ b/crates/nu_plugin_custom_values/src/main.rs @@ -4,22 +4,22 @@ mod second_custom_value; use cool_custom_value::CoolCustomValue; use nu_plugin::{serve_plugin, MsgPackSerializer, Plugin}; use nu_plugin::{EvaluatedCall, LabeledError}; -use nu_protocol::{Category, ShellError, Signature, Value}; +use nu_protocol::{Category, PluginSignature, ShellError, Value}; use second_custom_value::SecondCustomValue; struct CustomValuePlugin; impl Plugin for CustomValuePlugin { - fn signature(&self) -> Vec { + fn signature(&self) -> Vec { vec![ - Signature::build("custom-value generate") - .usage("Signature for a plugin that generates a custom value") + PluginSignature::build("custom-value generate") + .usage("PluginSignature for a plugin that generates a custom value") .category(Category::Experimental), - Signature::build("custom-value generate2") - .usage("Signature for a plugin that generates a different custom value") + PluginSignature::build("custom-value generate2") + .usage("PluginSignature for a plugin that generates a different custom value") .category(Category::Experimental), - Signature::build("custom-value update") - .usage("Signature for a plugin that updates a custom value") + PluginSignature::build("custom-value update") + .usage("PluginSignature for a plugin that updates a custom value") .category(Category::Experimental), ] } diff --git a/crates/nu_plugin_example/src/main.rs b/crates/nu_plugin_example/src/main.rs index d8e7ae207..2effdfe78 100644 --- a/crates/nu_plugin_example/src/main.rs +++ b/crates/nu_plugin_example/src/main.rs @@ -13,10 +13,10 @@ fn main() { // is added and used in nushell. // The steps are: // - The plugin is register. In this stage nushell calls the binary file of - // the plugin sending information using the encoded PluginCall::Signature object. + // the plugin sending information using the encoded PluginCall::PluginSignature object. // Use this encoded data in your plugin to design the logic that will return // the encoded signatures. - // Nushell is expecting and encoded PluginResponse::Signature with all the + // Nushell is expecting and encoded PluginResponse::PluginSignature with all the // plugin signatures // - When calling the plugin, nushell sends to the binary file the encoded // PluginCall::CallInfo which has all the call information, such as the diff --git a/crates/nu_plugin_example/src/nu/mod.rs b/crates/nu_plugin_example/src/nu/mod.rs index 9e2b57c6b..1a1d5f8cf 100644 --- a/crates/nu_plugin_example/src/nu/mod.rs +++ b/crates/nu_plugin_example/src/nu/mod.rs @@ -1,15 +1,29 @@ use crate::Example; use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; -use nu_protocol::{Category, Signature, SyntaxShape, Value}; +use nu_protocol::{Category, PluginExample, PluginSignature, SyntaxShape, Value}; impl Plugin for Example { - fn signature(&self) -> Vec { + 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("nu-example-1") - .usage("Signature test 1 for plugin. Returns Value::Nothing") + PluginSignature::build("nu-example-1") + .usage("PluginSignature 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") + .plugin_examples(vec![PluginExample { + example: "nu-example-1 3 bb".into(), + description: "running example with an int value and string value".into(), + result: None, + }]) + .category(Category::Experimental), + PluginSignature::build("nu-example-2") + .usage("PluginSignature 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')) @@ -17,17 +31,8 @@ impl Plugin for Example { .named("named", SyntaxShape::String, "named string", Some('n')) .rest("rest", SyntaxShape::String, "rest value string") .category(Category::Experimental), - Signature::build("nu-example-2") - .usage("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("nu-example-3") - .usage("Signature test 3 for plugin. Returns labeled error") + PluginSignature::build("nu-example-3") + .usage("PluginSignature 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')) diff --git a/crates/nu_plugin_gstat/src/nu/mod.rs b/crates/nu_plugin_gstat/src/nu/mod.rs index 56a7e3d6a..c3bb7bfc7 100644 --- a/crates/nu_plugin_gstat/src/nu/mod.rs +++ b/crates/nu_plugin_gstat/src/nu/mod.rs @@ -1,10 +1,10 @@ use crate::GStat; use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; -use nu_protocol::{Category, Signature, Spanned, SyntaxShape, Value}; +use nu_protocol::{Category, PluginSignature, Spanned, SyntaxShape, Value}; impl Plugin for GStat { - fn signature(&self) -> Vec { - vec![Signature::build("gstat") + fn signature(&self) -> Vec { + vec![PluginSignature::build("gstat") .usage("Get the git status of a repo") .optional("path", SyntaxShape::Filepath, "path to repo") .category(Category::Custom("prompt".to_string()))] diff --git a/crates/nu_plugin_inc/src/nu/mod.rs b/crates/nu_plugin_inc/src/nu/mod.rs index d3461ea4f..1c66c5c13 100644 --- a/crates/nu_plugin_inc/src/nu/mod.rs +++ b/crates/nu_plugin_inc/src/nu/mod.rs @@ -1,11 +1,11 @@ use crate::inc::SemVerAction; use crate::Inc; use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; -use nu_protocol::{ast::CellPath, Signature, SyntaxShape, Value}; +use nu_protocol::{ast::CellPath, PluginSignature, SyntaxShape, Value}; impl Plugin for Inc { - fn signature(&self) -> Vec { - vec![Signature::build("inc") + fn signature(&self) -> Vec { + vec![PluginSignature::build("inc") .usage("Increment a value or version. Optionally use the column of a table.") .optional("cell_path", SyntaxShape::CellPath, "cell path to update") .switch( diff --git a/crates/nu_plugin_query/src/nu/mod.rs b/crates/nu_plugin_query/src/nu/mod.rs index 641665f5c..65ca0e4c2 100644 --- a/crates/nu_plugin_query/src/nu/mod.rs +++ b/crates/nu_plugin_query/src/nu/mod.rs @@ -1,25 +1,25 @@ use crate::Query; use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; -use nu_protocol::{Category, Signature, Spanned, SyntaxShape, Value}; +use nu_protocol::{Category, PluginSignature, Spanned, SyntaxShape, Value}; impl Plugin for Query { - fn signature(&self) -> Vec { + fn signature(&self) -> Vec { vec![ - Signature::build("query") + PluginSignature::build("query") .usage("Show all the query commands") .category(Category::Filters), - Signature::build("query json") + PluginSignature::build("query json") .usage("execute json query on json file (open --raw | query json 'query string')") .required("query", SyntaxShape::String, "json query") .category(Category::Filters), - Signature::build("query xml") + PluginSignature::build("query xml") .usage("execute xpath query on xml") .required("query", SyntaxShape::String, "xpath query") .category(Category::Filters), - Signature::build("query web") + PluginSignature::build("query web") .usage("execute selector query on html/web") .named("query", SyntaxShape::String, "selector query", Some('q')) .switch("as-html", "return the query output as html", Some('m')) diff --git a/crates/nu_plugin_query/src/query.rs b/crates/nu_plugin_query/src/query.rs index cb7847aa4..651df7873 100644 --- a/crates/nu_plugin_query/src/query.rs +++ b/crates/nu_plugin_query/src/query.rs @@ -3,7 +3,7 @@ use crate::query_web::parse_selector_params; use crate::query_xml::execute_xpath_query; use nu_engine::documentation::get_flags_section; use nu_plugin::{EvaluatedCall, LabeledError, Plugin}; -use nu_protocol::{Signature, Spanned, Value}; +use nu_protocol::{PluginSignature, Spanned, Value}; use std::fmt::Write; #[derive(Default)] @@ -58,19 +58,19 @@ impl Query { } } -pub fn get_brief_subcommand_help(sigs: &[Signature]) -> String { +pub fn get_brief_subcommand_help(sigs: &[PluginSignature]) -> String { let mut help = String::new(); - let _ = write!(help, "{}\n\n", sigs[0].usage); - let _ = write!(help, "Usage:\n > {}\n\n", sigs[0].name); + let _ = write!(help, "{}\n\n", sigs[0].sig.usage); + let _ = write!(help, "Usage:\n > {}\n\n", sigs[0].sig.name); help.push_str("Subcommands:\n"); for x in sigs.iter().enumerate() { if x.0 == 0 { continue; } - let _ = writeln!(help, " {} - {}", x.1.name, x.1.usage); + let _ = writeln!(help, " {} - {}", x.1.sig.name, x.1.sig.usage); } - help.push_str(&get_flags_section(&sigs[0])); + help.push_str(&get_flags_section(&sigs[0].sig)); help }