### Basic serve_plugin Usage Example Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E This example demonstrates the basic setup for a Nu plugin using `serve_plugin`. It requires implementing the `Plugin` trait and defining a `main` function to start the plugin server. ```rust /// ```rust,no_run /// # use nu_plugin::* /// # use nu_protocol::{PluginSignature, Value}; /// # struct MyPlugin; /// # impl MyPlugin { fn new() -> Self { Self }} /// # impl Plugin for MyPlugin { /// # fn version(&self) -> String { "0.0.0".into() } /// # fn commands(&self) -> Vec>> {todo!()} /// # } /// fn main() { /// serve_plugin(&MyPlugin::new(), MsgPackSerializer) /// } /// ``` ``` -------------------------------- ### Provide Usage Examples for Plugin Command Source: https://docs.rs/nu-plugin/latest/nu_plugin/trait.PluginCommand.html?search=std%3A%3Avec Implement the `examples` method to offer usage examples in Nu. These examples can demonstrate pipelines and optionally include expected results for testing. ```rust fn examples(&self) -> Vec> ``` -------------------------------- ### Basic Plugin Server Setup Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search=std%3A%3Avec This snippet shows the basic `main` function setup for a Nu plugin, initializing and serving it with a specific encoder. ```rust use nu_plugin::* use nu_protocol::{PluginSignature, Value}; struct MyPlugin; impl MyPlugin { fn new() -> Self { Self }} impl Plugin for MyPlugin { fn version(&self) -> String { "0.0.0".into() } fn commands(&self) -> Vec>> {todo!()} } fn main() { serve_plugin(&MyPlugin::new(), MsgPackSerializer) } ``` -------------------------------- ### Render Examples for Signature Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/command.rs.html?search= Renders examples to their base value so they can be sent in the response to `Signature`. This function iterates through examples and converts custom values to their base representation. ```rust pub(crate) fn render_examples( plugin: &impl Plugin, engine: &EngineInterface, examples: &mut [PluginExample], ) -> Result<(), ShellError> { for example in examples { if let Some(ref mut value) = example.result { value.recurse_mut(&mut |value| { let span = value.span(); match value { Value::Custom { .. } => { let value_taken = std::mem::replace(value, Value::nothing(span)); let Value::Custom { val, .. } = value_taken else { unreachable!() }; *value = plugin.custom_value_to_base_value(engine, val.into_spanned(span))?; Ok::<_, ShellError>(()) } _ => Ok(()), } })?; } } Ok(()) } ``` -------------------------------- ### Main Entry Point for a Plugin Source: https://docs.rs/nu-plugin/latest/nu_plugin/fn.serve_plugin.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Example of how to use serve_plugin as the main entry point for a plugin. ```rust fn main() { serve_plugin(&MyPlugin::new(), MsgPackSerializer) } ``` -------------------------------- ### Get Help String Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html Retrieves the help string for the current command, equivalent to passing `--help`. ```rust pub fn get_help(&self) -> Result ``` -------------------------------- ### Get Command Help String Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Retrieves the help string for the current command, equivalent to passing `--help`. ```rust eprintln!("{}", engine.get_help()?); ``` -------------------------------- ### Basic Hello World Plugin Command Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/command.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates a simple plugin command that returns a static greeting. This example uses `SimplePluginCommand` for value-based I/O. ```rust use nu_plugin::*; use nu_protocol::{LabeledError, Signature, Type, Value}; struct HelloPlugin; struct Hello; impl SimplePluginCommand for Hello { type Plugin = HelloPlugin; fn name(&self) -> &str { "hello" } fn description(&self) -> &str { "Every programmer's favorite greeting" } fn signature(&self) -> Signature { Signature::build(PluginCommand::name(self)) .input_output_type(Type::Nothing, Type::String) } fn run( &self, plugin: &HelloPlugin, engine: &EngineInterface, call: &EvaluatedCall, input: &Value, ) -> Result { Ok(Value::string("Hello, World!".to_owned(), call.head)) } } impl Plugin for HelloPlugin { fn version(&self) -> String { "0.0.0".into() } fn commands(&self) -> Vec>> { vec![Box::new(Hello)] } } fn main() { serve_plugin(&HelloPlugin{}, MsgPackSerializer) } ``` -------------------------------- ### Main Entry Point for a New Plugin Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html This example shows how `serve_plugin` is typically used as the main entry point when creating a new plugin. It requires implementing the `Plugin` trait and providing a `PluginEncoder`. ```rust # use nu_plugin::* # use nu_protocol::{PluginSignature, Value}; # struct MyPlugin; # impl MyPlugin { fn new() -> Self { Self }} # impl Plugin for MyPlugin { fn version(&self) -> String { "0.0.0".into() } fn commands(&self) -> Vec>> {todo!();} } fn main() { serve_plugin(&MyPlugin::new(), MsgPackSerializer) } ``` -------------------------------- ### Serve Nu Plugin with MsgPack Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search= This is the main entry point for a Nu plugin. It initializes the plugin and starts serving requests using MsgPack serialization. Ensure the `MsgPackSerializer` is available and correctly implemented. ```rust # use nu_plugin::* # use nu_protocol::{PluginSignature, Value}; # struct MyPlugin; # impl MyPlugin { fn new() -> Self { Self }} # impl Plugin for MyPlugin { # fn version(&self) -> String { "0.0.0".into() } # fn commands(&self) -> Vec>> {todo!()} # } fn main() { serve_plugin(&MyPlugin::new(), MsgPackSerializer) } ``` -------------------------------- ### Basic Plugin Implementation Example Source: https://docs.rs/nu-plugin/latest/nu_plugin/trait.Plugin.html Demonstrates a minimal implementation of the Plugin trait for a 'hello' command. Includes defining the plugin struct, implementing required methods, and defining a simple command. ```rust struct HelloPlugin; struct Hello; impl Plugin for HelloPlugin { fn version(&self) -> String { env!("CARGO_PKG_VERSION").into() } fn commands(&self) -> Vec>> { vec![Box::new(Hello)] } } impl SimplePluginCommand for Hello { type Plugin = HelloPlugin; fn name(&self) -> &str { "hello" } fn description(&self) -> &str { "Every programmer's favorite greeting" } fn signature(&self) -> Signature { Signature::build(PluginCommand::name(self)) .input_output_type(Type::Nothing, Type::String) } fn run( &self, plugin: &HelloPlugin, engine: &EngineInterface, call: &EvaluatedCall, input: &Value, ) -> Result { Ok(Value::string("Hello, World!".to_owned(), call.head)) } } ``` -------------------------------- ### Implementing a basic Nushell plugin command Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/command.rs.html This example demonstrates how to implement the `PluginCommand` trait for a simple command that converts strings to lowercase. It shows the required methods like `name`, `description`, `signature`, and `run`. ```rust use nu_plugin::*; use nu_protocol::{LabeledError, PipelineData, Signals, Signature, Type, Value}; struct LowercasePlugin; struct Lowercase; impl PluginCommand for Lowercase { type Plugin = LowercasePlugin; fn name(&self) -> &str { "lowercase" } fn description(&self) -> &str { "Convert each string in a stream to lowercase" } fn signature(&self) -> Signature { Signature::build(PluginCommand::name(self)) .input_output_type(Type::List(Type::String.into()), Type::List(Type::String.into())) } fn run( &self, plugin: &LowercasePlugin, engine: &EngineInterface, call: &EvaluatedCall, input: PipelineData, ) -> Result { let span = call.head; Ok(input.map(move |value| { value.as_str() .map(|string| Value::string(string.to_lowercase(), span)) // Errors in a stream should be returned as values. .unwrap_or_else(|err| Value::error(err, span)) }, &Signals::empty())?) // Removed the extra `?` here } } impl Plugin for LowercasePlugin { fn version(&self) -> String { "0.0.0".into() } fn commands(&self) -> Vec>> { vec![Box::new(Lowercase)] } } fn main() { serve_plugin(&LowercasePlugin{}, MsgPackSerializer) } ``` -------------------------------- ### Format Value with User's Preferred Style Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/interface/mod.rs.html Example demonstrating how to format a Nu Value using the user's preferred style, obtained from the engine's configuration. ```rust # use nu_protocol::{Value, ShellError}; # use nu_plugin::EngineInterface; # fn example(engine: &EngineInterface, value: &Value) -> Result<(), ShellError> { let config = engine.get_config()?; eprintln!("{}", value.to_expanded_string(", ", &config)); # Ok(()) # } ``` -------------------------------- ### Get Dynamic Plugin Completions with Panic Handling Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html Fetches dynamic completion suggestions for a plugin command, handling potential panics during the process. Exits the process if a panic is caught. ```rust let items = if let Some(command) = commands.get(&name) { let arg_type = arg_type.into(); command.get_dynamic_completion( plugin, &engine, call, arg_type, #[expect(deprecated, reason = "internal usage")] nu_protocol::engine::ExperimentalMarker, ) } else { None }; let write_result = engine.write_completion_items(items).try_to_report(&engine); if let Err(err) = write_result { let _ = error_tx.send(err); } })); if unwind_result.is_err() { // Exit after unwind if a panic occurred std::process::exit(1) } ``` -------------------------------- ### Render Plugin Examples Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/command.rs.html This utility function iterates through `PluginExample`s and renders their results to a base value format. It handles custom values by converting them to their base representation using the plugin's `custom_value_to_base_value` method. ```rust /// Render examples to their base value so they can be sent in the response to `Signature`. pub(crate) fn render_examples( plugin: &impl Plugin, engine: &EngineInterface, examples: &mut [PluginExample], ) -> Result<(), ShellError> { for example in examples { if let Some(ref mut value) = example.result { value.recurse_mut(&mut |value| { let span = value.span(); match value { Value::Custom { .. } => { let value_taken = std::mem::replace(value, Value::nothing(span)); let Value::Custom { val, .. } = value_taken else { unreachable!() }; *value = plugin.custom_value_to_base_value(engine, val.into_spanned(span))?; Ok::<_, ShellError>(()) } _ => Ok(()), } })?; } } Ok(()) } ``` -------------------------------- ### Handle Plugin Signature Request Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html Generates and sends plugin command signatures back to NuShell, including rendered examples, for declaration definition. ```rust let sigs = commands .values() .map(|command| create_plugin_signature(command.deref())) .map(|mut sig| { render_examples(plugin, &engine, &mut sig.examples)?; Ok(sig) }) .collect::, ShellError>>() .try_to_report(&engine)?; engine.write_signature(sigs).try_to_report(&engine)? ``` -------------------------------- ### Basic PluginCommand Implementation Source: https://docs.rs/nu-plugin/latest/nu_plugin/trait.PluginCommand.html?search= An example implementation of the PluginCommand trait for a 'lowercase' command that converts string streams to lowercase. It defines the command's name, signature, and run logic. ```rust struct LowercasePlugin; struct Lowercase; impl PluginCommand for Lowercase { type Plugin = LowercasePlugin; fn name(&self) -> &str { "lowercase" } fn description(&self) -> &str { "Convert each string in a stream to lowercase" } fn signature(&self) -> Signature { Signature::build(PluginCommand::name(self)) .input_output_type(Type::List(Type::String.into()), Type::List(Type::String.into())) } fn run( &self, plugin: &LowercasePlugin, engine: &EngineInterface, call: &EvaluatedCall, input: PipelineData, ) -> Result { let span = call.head; Ok(input.map(move |value| { value.as_str() .map(|string| Value::string(string.to_lowercase(), span)) // Errors in a stream should be returned as values. .unwrap_or_else(|err| Value::error(err, span)) }, &Signals::empty())?) } } ``` -------------------------------- ### Handle Plugin Signature Call Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search= This snippet demonstrates how to handle a `ReceivedPluginCall::Signature` event. It retrieves command signatures, renders examples for each, and writes the collected signatures back to the NuShell engine. ```rust ReceivedPluginCall::Signature { engine } => { let sigs = commands .values() .map(|command| create_plugin_signature(command.deref())) .map(|mut sig| { render_examples(plugin, &engine, &mut sig.examples)?; Ok(sig) }) .collect::, ShellError>>() .try_to_report(&engine)?; engine.write_signature(sigs).try_to_report(&engine)?; } ``` -------------------------------- ### get_help Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Get the help string for the current command. This returns the same string as passing `--help` would, and can be used for the top-level command in a command group that doesn’t do anything on its own (e.g. `query`). ```APIDOC ## get_help ### Description Get the help string for the current command. This returns the same string as passing `--help` would, and can be used for the top-level command in a command group that doesn’t do anything on its own (e.g. `query`). ### Method `(&self) -> Result` ### Example ```rust eprintln!("{}", engine.get_help()?); ``` ``` -------------------------------- ### name Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.JsonSerializer.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Get the name of the JSON encoder. ```APIDOC ## impl PluginEncoder for JsonSerializer ### fn name(&self) -> &str The name of the encoder (e.g., `json`) ``` -------------------------------- ### type_id Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html Gets the `TypeId` of the object. This is useful for runtime type identification. ```APIDOC ## fn type_id ### Description Gets the `TypeId` of `self`. ### Signature `fn type_id(&self) -> TypeId` ``` -------------------------------- ### get_current_dir Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Get the current working directory from the engine. The result is always an absolute path. ```APIDOC ## get_current_dir ### Description Get the current working directory from the engine. The result is always an absolute path. ### Method `(&self) -> Result` ### Example ```rust engine.get_current_dir() // => "/home/user" ``` ``` -------------------------------- ### get_env_var Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Get an environment variable from the engine. Returns `Some(value)` if present, and `None` if not found. ```APIDOC ## get_env_var ### Description Get an environment variable from the engine. Returns `Some(value)` if present, and `None` if not found. ### Method `(&self, name: impl Into) -> Result, ShellError>` ### Example Get `$env.PATH`: ```rust engine.get_env_var("PATH") // => Ok(Some(Value::List([...]))) ``` ``` -------------------------------- ### Basic Hello World Plugin Command Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/command.rs.html Demonstrates a simple 'hello' command that returns a fixed string. It defines the command's name, description, and signature, and implements the `run` method to produce the output. ```rust # use nu_plugin::* # use nu_protocol::{LabeledError, Signature, Type, Value}; struct HelloPlugin; struct Hello; impl SimplePluginCommand for Hello { type Plugin = HelloPlugin; fn name(&self) -> &str { "hello" } fn description(&self) -> &str { "Every programmer\'s favorite greeting" } fn signature(&self) -> Signature { Signature::build(PluginCommand::name(self)) .input_output_type(Type::Nothing, Type::String) } fn run( &self, plugin: &HelloPlugin, engine: &EngineInterface, call: &EvaluatedCall, input: &Value, ) -> Result { Ok(Value::string("Hello, World!".to_owned(), call.head)) } } # impl Plugin for HelloPlugin { # fn version(&self) -> String { # "0.0.0".into() # } # fn commands(&self) -> Vec>> { # vec![Box::new(Hello)] # } # } # # fn main() { # serve_plugin(&HelloPlugin{}, MsgPackSerializer) # } ``` -------------------------------- ### Basic SimplePluginCommand Implementation Source: https://docs.rs/nu-plugin/latest/nu_plugin/trait.SimplePluginCommand.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates a minimal implementation of the SimplePluginCommand trait for a 'hello' command. This includes defining the command's name, signature, description, and the 'run' method which returns a static string. ```rust struct HelloPlugin; struct Hello; impl SimplePluginCommand for Hello { type Plugin = HelloPlugin; fn name(&self) -> &str { "hello" } fn description(&self) -> &str { "Every programmer's favorite greeting" } fn signature(&self) -> Signature { Signature::build(PluginCommand::name(self)) .input_output_type(Type::Nothing, Type::String) } fn run( &self, plugin: &HelloPlugin, engine: &EngineInterface, call: &EvaluatedCall, input: &Value, ) -> Result { Ok(Value::string("Hello, World!".to_owned(), call.head)) } } ``` -------------------------------- ### Get Flag When Not Present Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EvaluatedCall.html?search=u32+-%3E+bool Retrieves a flag value that is not present. Use when a flag is optional. ```rust let foo = call.get_flag::("foo"); assert_eq!(foo.unwrap(), None); ``` -------------------------------- ### Get Dynamic Completion Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search= Handles requests for dynamic completions based on the provided engine and info. ```rust ReceivedPluginCall::GetCompletion { engine, info } => { get_dynamic_completion(engine, info) } ``` -------------------------------- ### Plugin Commands Implementation Source: https://docs.rs/nu-plugin/latest/nu_plugin/trait.Plugin.html Illustrates the implementation for the `commands` method, which returns a vector of all supported plugin commands. This method is called once at startup. ```rust fn commands(&self) -> Vec>> { vec![Box::new(Hello)] } ``` -------------------------------- ### get_config Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Get the full shell configuration from the engine. As this is quite a large object, it is provided on request only. ```APIDOC ## get_config ### Description Get the full shell configuration from the engine. As this is quite a large object, it is provided on request only. ### Method `(&self) -> Result, ShellError>` ### Example Format a value in the user’s preferred way: ```rust let config = engine.get_config()?; eprintln!("{}", value.to_expanded_string(", ", &config)); ``` ``` -------------------------------- ### Get Plugin-Specific Configuration Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Fetches the configuration specific to the current plugin. This configuration is typically found in `$env.config.plugins.NAME`. ```rust let config = engine.get_plugin_config()?; eprintln!("{:?}", config); ``` -------------------------------- ### Get Flag with Integer Value Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EvaluatedCall.html?search=u32+-%3E+bool Retrieves an integer flag value. Use when the flag is expected to be an integer. ```rust let foo = call.get_flag::("foo"); assert_eq!(foo.unwrap(), Some(123)); ``` -------------------------------- ### serve_plugin_io Command Handling and Thread Spawning Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search=u32+-%3E+bool Initializes command handling, spawns a reader thread for the engine interface, and sets up a scope for handling plugin calls. ```rust let (error_tx, error_rx) = mpsc::channel(); // Build commands map, to make running a command easier let mut commands: HashMap = HashMap::new(); for command in plugin.commands() { if let Some(previous) = commands.insert(command.name().into(), command) { eprintln!( "Plugin `{plugin_name}` warning: command `{}` shadowed by another command with the \ same name. Check your commands' `name()` methods", previous.name() ); } } let mut manager = EngineInterfaceManager::new(output()); let call_receiver = manager .take_plugin_call_receiver() .expect("take_plugin_call_receiver returned None"); // We need to hold on to the interface to keep the manager alive. We can drop it at the end let interface = manager.get_interface(); // Send Hello message interface.hello()?; { // Spawn the reader thread let error_tx = error_tx.clone(); std::thread::Builder::new() .name("engine interface reader".into()) .spawn(move || { // Report the error on the channel if we get an error if let Err(err) = manager.consume_all(input()) { let _ = error_tx.send(ServePluginError::from(err)); } }) .map_err(ServePluginError::ThreadSpawnError)?; } // Handle each Run plugin call on a thread thread::scope(|scope| { let run = |engine, call_info| { // SAFETY: It should be okay to use `AssertUnwindSafe` here, because we don't use any // of the references after we catch the unwind, and immediately exit. let unwind_result = std::panic::catch_unwind(AssertUnwindSafe(|| { let CallInfo { name, call, input } = call_info; let result = if let Some(command) = commands.get(&name) { command.run(plugin, &engine, &call, input) } else { Err( LabeledError::new(format!("Plugin command not found: `{name}`")) .with_label( format!("plugin `{plugin_name}` doesn't have this command"), ``` -------------------------------- ### serve_plugin_io Function Body - Initialization Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search=std%3A%3Avec Initializes channels, a command map, and the `EngineInterfaceManager` for the `serve_plugin_io` function. It also sends a 'Hello' message to the engine. ```rust let (error_tx, error_rx) = mpsc::channel(); // Build commands map, to make running a command easier let mut commands: HashMap = HashMap::new(); for command in plugin.commands() { if let Some(previous) = commands.insert(command.name().into(), command) { eprintln!( "Plugin `{plugin_name}` warning: command `{}` shadowed by another command with the \ same name. Check your commands' `name()` methods", previous.name() ); } } let mut manager = EngineInterfaceManager::new(output()); let call_receiver = manager .take_plugin_call_receiver() .expect("take_plugin_call_receiver returned None"); // We need to hold on to the interface to keep the manager alive. We can drop it at the end let interface = manager.get_interface(); // Send Hello message interface.hello()?; ``` -------------------------------- ### Get Current Working Directory Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Obtains the current working directory from the engine. The returned path is always absolute. ```rust engine.get_current_dir() // => "/home/user" ``` -------------------------------- ### Get the Span of a flag in EvaluatedCall Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EvaluatedCall.html?search=u32+-%3E+bool Retrieves the Span associated with a flag's name, useful for error reporting. ```rust call.get_flag_span("foo") ``` -------------------------------- ### Plugin Communication Modes Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search=u32+-%3E+bool Demonstrates how `serve_plugin` handles different communication modes, including stdio and local sockets, based on command-line arguments. ```rust # use nu_plugin::* # use nu_protocol::{PluginSignature, Value}; # struct MyPlugin; # impl MyPlugin { fn new() -> Self { Self }} # impl Plugin for MyPlugin { # fn version(&self) -> String { "0.0.0".into() } # fn commands(&self) -> Vec>> {todo!()} # } # fn print_help(_plugin: &MyPlugin, _encoder: impl PluginEncoder) { todo!() } # fn serve_plugin_io( # _plugin: &MyPlugin, # _plugin_name: &str, # _reader: impl FnOnce() -> (impl std::io::Read, impl PluginEncoder), # _writer: impl FnOnce() -> (impl std::io::Write, impl PluginEncoder), # ) -> Result<(), ServePluginError> { # Ok(()) # } # enum CommunicationMode { # Stdio, # LocalSocket(String) # } # impl CommunicationMode { # fn connect_as_client(&self) -> Result { # match self { # CommunicationMode::Stdio => Ok(ClientCommunicationIo::Stdio(std::io::empty(), std::io::sink())), # CommunicationMode::LocalSocket(_) => Ok(ClientCommunicationIo::LocalSocket { read_in: std::io::empty(), write_out: std::io::sink() }) # } # } # } # enum ClientCommunicationIo { # Stdio(std::io::Empty, std::io::Sink), # LocalSocket { read_in: std::io::Empty, write_out: std::io::Sink }, # } # const OUTPUT_BUFFER_SIZE: usize = 1024; # #[derive(Debug, Error)] # pub enum ServePluginError { # UnreportedError(String) # } # impl PluginEncoder for MsgPackSerializer { fn name(&self) -> String { "msgpack".into() } } # struct MsgPackSerializer; # impl Clone for MsgPackSerializer { fn clone(&self) -> Self { Self } } # impl std::io::Write for std::io::Sink { fn write(&mut self, buf: &[u8]) -> Result { Ok(buf.len()) } fn flush(&mut self) -> Result<(), std::io::Error> { Ok(()) } } # impl std::io::Read for std::io::Empty { fn read(&mut self, buf: &mut [u8]) -> Result { Ok(0) } } # impl std::io::Write for std::io::Empty { fn write(&mut self, buf: &[u8]) -> Result { Ok(buf.len()) } fn flush(&mut self) -> Result<(), std::io::Error> { Ok(()) } } # impl std::io::Read for std::io::Sink { fn read(&mut self, buf: &mut [u8]) -> Result { Ok(0) } } # mod env { pub fn args_os() -> std::iter::Empty { std::iter::empty() } pub fn current_exe() -> Result { Ok(std::path::PathBuf::from("nu_plugin_test")) } } # fn serve_plugin(plugin: &impl Plugin, encoder: impl PluginEncoder + 'static) { let args: Vec = env::args_os().skip(1).collect(); let exe = std::env::current_exe().ok(); let plugin_name: String = exe .as_ref() .and_then(|path| path.file_stem()) .map(|stem| stem.to_string_lossy().into_owned()) .map(|stem| { stem.strip_prefix("nu_plugin_") .map(|s| s.to_owned()) .unwrap_or(stem) }) .unwrap_or_else(|| "(unknown)".into()); if args.is_empty() || args[0] == "-h" || args[0] == "--help" { print_help(plugin, encoder); std::process::exit(0) } let mode = if args[0] == "--stdio" && args.len() == 1 { CommunicationMode::Stdio } else if args[0] == "--local-socket" && args.len() == 2 { #[cfg(feature = "local-socket")] { CommunicationMode::LocalSocket((&args[1]).into()) } #[cfg(not(feature = "local-socket"))] { eprintln!(ירת{plugin_name}: local socket mode is not supported"); std::process::exit(1); } } else { eprintln!( ירת{}: This plugin must be run from within Nushell. See `plugin add --help` for details on how to use plugins., env::current_exe() .map(|path| path.display().to_string()) .unwrap_or_else(|_| "plugin".into()) ); eprintln!( "If you are running from Nushell, this plugin may be incompatible with the version of nushell you are using." ); std::process::exit(1) }; let encoder_clone = encoder.clone(); let result = match mode.connect_as_client() { Ok(ClientCommunicationIo::Stdio(stdin, mut stdout)) => { tell_nushell_encoding(&mut stdout, &encoder).expect("failed to tell nushell encoding"); serve_plugin_io( plugin, &plugin_name, move || (stdin.lock(), encoder_clone), move || (stdout, encoder), ) } #[cfg(feature = "local-socket")] Ok(ClientCommunicationIo::LocalSocket { read_in, mut write_out, }) => { use std::io::{BufReader, BufWriter}; use std::sync::Mutex; tell_nushell_encoding(&mut write_out, &encoder) .expect("failed to tell nushell encoding"); let read = BufReader::with_capacity(OUTPUT_BUFFER_SIZE, read_in); let write = Mutex::new(BufWriter::with_capacity(OUTPUT_BUFFER_SIZE, write_out)); serve_plugin_io( plugin, &plugin_name, move || (read, encoder_clone), move || (write, encoder), ) } Err(err) => { eprintln!(ירת{plugin_name}: failed to connect: {err:?}"); std::process::exit(1); } }; match result { Ok(()) => (), Err(ServePluginError::UnreportedError(err)) => { eprintln!("Plugin `{plugin_name}` error: {err}"); std::process::exit(1); } Err(_) => std::process::exit(1), } } ``` -------------------------------- ### Try From Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.DynamicCompletionCall.html?search= Performs a conversion from one type to another, returning a Result. ```APIDOC ## fn try_from(value: U) -> Result>::Error> ### Description Performs the conversion. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response None #### Response Example None ``` -------------------------------- ### write_signature Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/interface/mod.rs.html Writes a call response containing plugin signatures to the engine. Custom values in examples are rendered using `to_base_value()`. ```APIDOC ## write_signature ### Description Writes a call response containing plugin signatures to the engine. Custom values in examples are rendered using `to_base_value()`. ### Method `pub(crate) fn write_signature(&self, signature: Vec) -> Result<(), ShellError>` ### Parameters - `signature`: `Vec` - A vector of plugin signatures to send to the engine. ``` -------------------------------- ### Serving Plugin via Stdio Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search=std%3A%3Avec Handles serving the plugin when using standard input/output for communication. It sets up buffered readers and writers. ```rust Ok(ClientCommunicationIo::Stdio(stdin, mut stdout)) => { tell_nushell_encoding(&mut stdout, &encoder).expect("failed to tell nushell encoding"); serve_plugin_io( plugin, &plugin_name, move || (stdin.lock(), encoder_clone), move || (stdout, encoder), ) } ``` -------------------------------- ### Write Plugin Signatures Response Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/interface/mod.rs.html Writes a PluginCallResponse::Signature to the engine. Custom values in examples are rendered using to_base_value(). ```rust pub(crate) fn write_signature( &self, signature: Vec, ) -> Result<(), ShellError> { let response = PluginCallResponse::Signature(signature); self.write(PluginOutput::CallResponse(self.context()?, response))?; self.flush() } ``` -------------------------------- ### Print Plugin Help Information Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search= Generates and prints help information for the plugin, including its name, version, and available commands. ```rust fn print_help(plugin: &impl Plugin, encoder: impl PluginEncoder) { use std::fmt::Write; println!("Nushell Plugin"); println!("Encoder: {}", encoder.name()); println!("Version: {}", plugin.version()); // Determine the plugin name let exe = std::env::current_exe().ok(); let plugin_name: String = exe .as_ref() .map(|stem| stem.to_string_lossy().into_owned()) .unwrap_or_else(|| "(unknown)".into()); println!("Plugin file path: {plugin_name}"); let mut help = String::new(); let help_style = HelpStyle::default(); plugin.commands().into_iter().for_each(|command| { let signature = command.signature(); let res = write!(help, "\nCommand: {}", command.name()) .and_then(|_| writeln!(help, "\nDescription:\n > {}", command.description())) .and_then(|_| { if !command.extra_description().is_empty() { ``` -------------------------------- ### Get Engine Configuration Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/interface/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Retrieves the full shell configuration from the engine. This is provided on demand due to its potentially large size. ```rust pub fn get_config(&self) -> Result, ShellError> { // ... implementation details ... } ``` -------------------------------- ### Serve Plugin IO Function Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/mod.rs.html?search= The `serve_plugin_io` function serves a plugin with custom input and output streams, offering more control than the standard `serve_plugin`. It manages command registration, interface initialization, and thread spawning for input reading and command handling. ```rust pub fn serve_plugin_io< I: PluginRead + 'static, O: PluginWrite + 'static, >( plugin: &impl Plugin, plugin_name: &str, input: impl FnOnce() -> I + Send + 'static, output: impl FnOnce() -> O + Send + 'static, ) -> Result<(), ServePluginError> where I: PluginRead + 'static, O: PluginWrite + 'static, { let (error_tx, error_rx) = mpsc::channel(); // Build commands map, to make running a command easier let mut commands: HashMap = HashMap::new(); for command in plugin.commands() { if let Some(previous) = commands.insert(command.name().into(), command) { eprintln!( "Plugin `{plugin_name}` warning: command `{}` shadowed by another command with the same name. Check your commands' `name()` methods", previous.name() ); } } let mut manager = EngineInterfaceManager::new(output()); let call_receiver = manager .take_plugin_call_receiver() // This expect should be totally safe, as we just created the manager .expect("take_plugin_call_receiver returned None"); // We need to hold on to the interface to keep the manager alive. We can drop it at the end let interface = manager.get_interface(); // Send Hello message interface.hello()?; { // Spawn the reader thread let error_tx = error_tx.clone(); std::thread::Builder::new() .name("engine interface reader".into()) .spawn(move || { // Report the error on the channel if we get an error if let Err(err) = manager.consume_all(input()) { let _ = error_tx.send(ServePluginError::from(err)); } }) .map_err(ServePluginError::ThreadSpawnError)?; } // Handle each Run plugin call on a thread thread::scope(|scope| { let run = |engine, call_info| { // SAFETY: It should be okay to use `AssertUnwindSafe` here, because we don't use any // of the references after we catch the unwind, and immediately exit. let unwind_result = std::panic::catch_unwind(AssertUnwindSafe(|| { let CallInfo { name, call, input } = call_info; let result = if let Some(command) = commands.get(&name) { command.run(plugin, &engine, &call, input) } else { Err( LabeledError::new(format!("Plugin command not found: `{name}`")) .with_label( format!("plugin `{plugin_name}` doesn't have this command"), ``` -------------------------------- ### Get Shell Configuration Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Retrieves the full shell configuration from the engine. This is provided on request due to its potentially large size. ```rust let config = engine.get_config()?; ``` -------------------------------- ### Get All Environment Variables Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Retrieves all environment variables from the engine as a HashMap. Prefer `.get_env_var()` for specific variables to avoid overhead. ```rust engine.get_env_vars() // => Ok({"PATH": Value::List([...]), ...}) ``` -------------------------------- ### EngineInterfaceManager Initialization Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/interface/mod.rs.html Illustrates the initialization of the EngineInterfaceManager with its state and communication channels. ```rust EngineInterfaceManager { state: Arc::new(EngineInterfaceState { protocol_info: protocol_info_mut.reader(), engine_call_id_sequence: Sequence::default(), stream_id_sequence: Sequence::default(), engine_call_subscription_sender: subscription_tx, writer: Box::new(writer), signals: Signals::new(Arc::new(AtomicBool::new(false))), signal_handlers: Handlers::new(), }), protocol_info_mut, plugin_call_sender: Some(plug_tx), plugin_call_receiver: Some(plug_rx), engine_call_subscriptions: BTreeMap::new(), engine_call_subscription_receiver: subscription_rx, stream_manager: StreamManager::new(), } ``` -------------------------------- ### Send Hello Protocol Info Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/interface/mod.rs.html?search= Writes the Hello message with default ProtocolInfo to the engine. Ensures the message is flushed. ```rust pub(crate) fn hello(&self) -> Result<(), ShellError> { self.write(PluginOutput::Hello(ProtocolInfo::default()))?; self.flush() } ``` -------------------------------- ### Get Environment Variable Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=u32+-%3E+bool Retrieves a specific environment variable from the engine. Returns `Some(value)` if the variable exists, otherwise `None`. ```rust engine.get_env_var("PATH") // => Ok(Some(Value::List([...]))) ``` -------------------------------- ### OwoColorize Methods Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Methods for colorizing output. ```APIDOC ## fn fg(&self) -> FgColorDisplay<'_, C, Self> where C: Color, ### Description Set the foreground color generically. ### Parameters - **C**: Color - The color type. ## fn bg(&self) -> BgColorDisplay<'_, C, Self> where C: Color, ### Description Set the background color generically. ### Parameters - **C**: Color - The color type. ## fn black(&self) -> FgColorDisplay<'_, Black, Self> ### Description Change the foreground color to black. ## fn on_black(&self) -> BgColorDisplay<'_, Black, Self> ### Description Change the background color to black. ## fn red(&self) -> FgColorDisplay<'_, Red, Self> ### Description Change the foreground color to red. ## fn on_red(&self) -> BgColorDisplay<'_, Red, Self> ### Description Change the background color to red. ## fn green(&self) -> FgColorDisplay<'_, Green, Self> ### Description Change the foreground color to green. ## fn on_green(&self) -> BgColorDisplay<'_, Green, Self> ### Description Change the background color to green. ## fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self> ### Description Change the foreground color to yellow. ## fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self> ### Description Change the background color to yellow. ## fn blue(&self) -> FgColorDisplay<'_, Blue, Self> ### Description Change the foreground color to blue. ## fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self> ### Description Change the background color to blue. ## fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self> ### Description Change the foreground color to magenta. ## fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self> ### Description Change the background color to magenta. ## fn purple(&self) -> FgColorDisplay<'_, Magenta, Self> ### Description Change the foreground color to purple. ## fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self> ### Description Change the background color to purple. ## fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self> ### Description Change the foreground color to cyan. ## fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self> ### Description Change the background color to cyan. ## fn white(&self) -> FgColorDisplay<'_, White, Self> ### Description Change the foreground color to white. ## fn on_white(&self) -> BgColorDisplay<'_, White, Self> ### Description Change the background color to white. ## fn default_color(&self) -> FgColorDisplay<'_, Default, Self> ### Description Change the foreground color to the terminal default. ## fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self> ### Description Change the background color to the terminal default. ## fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self> ### Description Change the foreground color to bright black. ``` -------------------------------- ### Get Flag with Incorrect Type Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EvaluatedCall.html?search=u32+-%3E+bool Handles cases where a flag is provided but with an incorrect type. Use to validate input types. ```rust let foo = call.get_flag::("foo"); assert!(foo.is_err()); ``` -------------------------------- ### Get a positional argument by index from EvaluatedCall Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EvaluatedCall.html?search=u32+-%3E+bool Retrieves a positional argument by its zero-based index. Returns None if the index is out of bounds. ```rust let arg = match call.nth(1) { Some(Value::String { val, .. }) => val, _ => panic!(), }; assert_eq!(arg, "b".to_owned()); let arg = call.nth(7); assert!(arg.is_none()); ``` -------------------------------- ### Get the Value of a named argument in EvaluatedCall Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.EvaluatedCall.html?search=u32+-%3E+bool Retrieves the Value associated with a named argument. Returns None if the argument is not present. ```rust let opt_foo = match call.get_flag_value("foo") { Some(Value::Int { val, .. }) => Some(val), None => None, _ => panic!(), }; assert_eq!(opt_foo, Some(123)); ``` ```rust let opt_foo = match call.get_flag_value("foo") { Some(Value::Int { val, .. }) => Some(val), None => None, _ => panic!(), }; assert_eq!(opt_foo, None); ``` -------------------------------- ### SimplePluginCommand::description Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/command.rs.html?search= Provides a brief description of the command's purpose, which will be displayed in Nushell's help output. ```APIDOC ## description ### Description Get a short description of the command's functionality for use in help messages. ### Method `description(&self) -> &str` ### Parameters None ### Request Example None ### Response #### Success Response - **&str**: The description of the command. #### Response Example ```json { "example": "A brief explanation of what this command does." } ``` ``` -------------------------------- ### Get Plugin Call Context Source: https://docs.rs/nu-plugin/latest/src/nu_plugin/plugin/interface/mod.rs.html?search=u32+-%3E+bool Retrieves the current plugin call context, returning an error if called outside of an active call. ```rust fn context(&self) -> Result { self.context.ok_or_else(|| ShellError::NushellFailed { msg: "Tried to call an EngineInterface method that requires a call context \ outside of one" .into(), }) } ``` -------------------------------- ### Get Type ID for Generic Type T Source: https://docs.rs/nu-plugin/latest/nu_plugin/struct.JsonSerializer.html?search=std%3A%3Avec Implements the `type_id` method for generic types `T` that are `'static` and `?Sized`, returning the `TypeId` of the instance. ```rust fn type_id(&self) -> TypeId ```