Home Explore Blog CI



nushell

6th chunk of `contributor-book/plugins.md`
fea2ed62e74996813fee9bc41ca31034d03b0a7063c10e720000000100001004
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.

Title: Plugin Configuration and Evaluating Closures
Summary
This section provides a comprehensive example of how to retrieve and use plugin configurations within a Nushell plugin, specifically for a 'motd' (message of the day) plugin. It demonstrates how to access configuration settings from the `$env.config.plugins` environment variable using `EngineInterface::get_plugin_config` and handle cases where the configuration or specific keys are missing. Furthermore, the section explains how plugins can accept and evaluate closures using `EngineInterface::eval_closure`, providing an example of a `my-each` plugin that applies a closure to each element of a list. It also notes the current limitation that closures can only refer to values valid for plugin transmission and that custom values from other plugins are not yet supported.