impl Plugin for LenPlugin {
fn version(&self) -> String {
env!("CARGO_PKG_VERSION").into()
}
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
vec![
Box::new(Len),
]
}
}
```
Again, we use a unit struct for `LenPlugin`, but this is the recommended place to put plugin state if needed. All commands also get a reference to the plugin type. This is what we eventually pass to `serve_plugin()` in `main()`.
`Plugin` has two required methods: `version()`, which reports the plugin's version back to Nu, and `commands()`, which initializes the plugin's commands. A boxed `dyn` reference is used so that we can keep all of the different command types in the single list. Dispatch by command name is automatically handled in `serve_plugin()` by looking at the name defined in the signature - in our case, that's `len`. A plugin can contain many commands, so if you end up adding more, just add them to the list returned by `commands()`.
For the version, we just use the `CARGO_PKG_VERSION` environment variable available at compile-time in order to get our plugin's version from Cargo.
Lastly, let's look at the top of the file:
```rust
use nu_plugin::{serve_plugin, JsonSerializer, EvaluatedCall};
use nu_plugin::{Plugin, PluginCommand, SimplePluginCommand, EngineInterface};
use nu_protocol::{LabeledError, Signature, Type, Value};
```
Here we import everything we need -- types and functions -- to be able to create our plugin.
Once we have finished our plugin, to use it all we need to do is install it.
```nu
> cargo install --path . --locked
# nushell only (run with `nu -c` if not in nushell)
> plugin add ~/.cargo/bin/nu_plugin_len # add .exe on Windows
```
If you're already running `nu` during the installation process of your plugin, ensure you restart `nu` so that it can load your plugin, or call `plugin use` to load it immediately:
```nu
> plugin use len # the name of the plugin (without `nu_plugin_`)
```
Once `nu` starts up, it will discover the plugin and add its commands to the scope.
```nu
nu
"hello" | len
# => 5
help len
# => calculates the length of its input
# =>
# => Usage:
# => > len
# =>
# => Flags:
# => -h, --help - Display the help message for this command
# =>
# => Signatures:
# => <string> | len -> <int>
```
Run `plugin list` to see all plugins currently registered and available to this Nu session, including whether or not they are running, and their process ID if so.
## Using streams in plugins
The `SimplePluginCommand` trait that we just implemented for our plugin does not support streaming input or output. If we want to extend our plugin to support determining the lengths of lists, it would be helpful to not have to consume an entire list that is a stream. We can do this by implementing `PluginCommand` instead.
```rust
// add these imports:
use nu_protocol::{IntoPipelineData, PipelineData};
// ...
// change SimplePluginCommand to PluginCommand:
impl PluginCommand for Len {
type Plugin = LenPlugin;
// ...
fn signature(&self) -> Signature {
// ... add the list type to the signature
Signature::build(PluginCommand::name(self))
.input_output_types(vec![
(Type::String, Type::Int),
(Type::List(Type::Any.into()), Type::Int),
])
}
// ... and change input and output types to PipelineData
fn run(
&self,
_plugin: &LenPlugin,
_engine: &EngineInterface,
call: &EvaluatedCall,
input: PipelineData,
) -> Result<PipelineData, LabeledError> {
// Check if the input is a stream or list
match input {
PipelineData::ListStream(..) |
PipelineData::Value(Value::List { .. }, _) => {
// Count the iterable's elements
let length = input.into_iter().count();
Ok(
Value::int(length as i64, call.head).into_pipeline_data()
)