The plugin configuration can be retrieved with [`EngineInterface::get_plugin_config`](https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html#method.get_plugin_config).
```rust
use nu_plugin::*;
use nu_protocol::{Signature, Type, Value};
struct MotdPlugin;
impl Plugin for MotdPlugin {
fn version(&self) -> String {
env!("CARGO_PKG_VERSION").into()
}
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
vec![
Box::new(Motd),
]
}
}
struct Motd;
impl SimplePluginCommand for Motd {
type Plugin = MotdPlugin;
fn name(&self) -> &str {
"motd"
}
fn description(&self) -> &str {
"Message of the day"
}
fn signature(&self) -> Signature {
Signature::build(PluginCommand::name(self))
.input_output_type(Type::Nothing, Type::String)
}
fn run(
&self,
_plugin: &MotdPlugin,
engine: &EngineInterface,
call: &EvaluatedCall,
_input: &Value,
) -> Result<Value, LabeledError> {
if let Some(config) = engine.get_plugin_config()? {
let message = config.get_data_by_key("message")
.ok_or_else(
|| LabeledError::new("Message not present in config")
.with_label("add the `message` key here", config.span())
)?;
Ok(Value::string(message.as_str()?, call.head))
} else {
Err(LabeledError::new("Config for `motd` not set in $env.config.plugins"))
}
}
}
fn main() {
serve_plugin(&MotdPlugin, MsgPackSerializer)
}
```
Example:
```nu
> $env.config.plugins.motd = {message: "Nushell rocks!"}
> motd
Nushell rocks!
```
For a full example, see [`nu_plugin_example`](https://github.com/nushell/plugin-examples/tree/main/rust/nu_plugin_example).
## Evaluating closures
Plugins can accept and evaluate closures using [`EngineInterface::eval_closure`](https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html#method.eval_closure) or [`eval_closure_with_stream`](https://docs.rs/nu-plugin/latest/nu_plugin/struct.EngineInterface.html#method.eval_closure_with_stream).
```rust
use nu_plugin::*;
use nu_protocol::{PipelineData, Signature, SyntaxShape, Type, Value};
struct MyEachPlugin;
impl Plugin for MyEachPlugin {
fn version(&self) -> String {
env!("CARGO_PKG_VERSION").into()
}
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
vec![
Box::new(MyEach),
]
}
}
struct MyEach;
impl PluginCommand for MyEach {
type Plugin = MyEachPlugin;
fn name(&self) -> &str {
"my-each"
}
fn description(&self) -> &str {
"Run closure on each element of a list"
}
fn signature(&self) -> Signature {
Signature::build(PluginCommand::name(self))
.required(
"closure",
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
"The closure to evaluate",
)
.input_output_type(Type::ListStream, Type::ListStream)
}
fn run(
&self,
_plugin: &MyEachPlugin,
engine: &EngineInterface,
call: &EvaluatedCall,
input: PipelineData,
) -> Result<PipelineData, LabeledError> {
let engine = engine.clone();
let closure = call.req(0)?;
Ok(input.map(move |item| {
let span = item.span();
engine.eval_closure(&closure, vec![item.clone()], Some(item))
.unwrap_or_else(|err| Value::error(err, span))
}, None)?)
}
}
fn main() {
serve_plugin(&MyEachPlugin, MsgPackSerializer)
}
```
`my-each` works just like `each`:
```nu
> [1 2 3] | my-each { |i| $i * 2 }
╭───┬───╮
│ 0 │ 2 │
│ 1 │ 4 │
│ 2 │ 6 │
╰───┴───╯
```
At present, the closures can only refer to values that would be valid to send to the plugin. This means that custom values from other plugins are not allowed. This is likely to be fixed in a future release.