type Plugin = LenPlugin;
// ...
}
```
We first specify the plugin type our command expects. This allows us to receive a reference to it in `run()`, which we can use for shared state between commands.
```rust
impl SimplePluginCommand for Len {
// ...
fn name(&self) -> &str {
"len"
}
fn description(&self) -> &str {
"calculates the length of its input"
}
fn signature(&self) -> Signature {
Signature::build(PluginCommand::name(self))
.input_output_type(Type::String, Type::Int)
}
// ...
}
```
There are a few methods required for this implementation. We first define the `name` of the command, which is what the user will type at the prompt or in their script to run the command. The `description` is also required, which is a short documentation string for users to know what the command does, and is displayed along with completions and in `help`. Finally, we define the `signature`, which specifies arguments and types for the command.
We tell Nu that the name is "len", give it a basic description for `help` to display and declare that we expect to be passed a string and will return an integer.
Next, in the `run` implementation, we describe how to do work as values flow into this plugin. Here, we receive a `Value` type that we expect to be a string. We also return either `Value` or an error.
```rust
impl SimplePluginCommand for Len {
// ...
fn run(
&self,
_plugin: &LenPlugin,
_engine: &EngineInterface,
call: &EvaluatedCall,
input: &Value,
) -> Result<Value, LabeledError> {
let span = input.span();
match input {
Value::String { val, .. } => Ok(
Value::int(val.len() as i64, span)
),
_ => Err(
LabeledError::new("Expected String input from pipeline")
.with_label(
format!("requires string input; got {}", input.get_type()),
call.head,
)
),
}
}
}
```
We use Rust's pattern matching to check the type of the `Value` coming in, and then operate with it if it's a string. The value also contains a `span` so it carries with it where the value came from. If the value isn't a string, we give an error and let the user know where the value came from that is causing the problem. On error, we use `call.head` as the span so that Nu can underline the offending command name in the error message.
Our `Len` command doesn't require any parameters, but if it did we'd get them from the `EvaluatedCall`.
```rust
struct Len;
```
`Len` is defined as a unit struct, with no fields, and this is the most common type definition for a command in a plugin. However, you may choose to keep state here if you want to - every call of `len` shares the same reference.
Above that, let's have a look at the definition of `LenPlugin`, which implements the `Plugin` trait:
```rust
struct LenPlugin;
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()`.