Home Explore Blog CI



nushell

3rd chunk of `contributor-book/plugins.md`
0987001089f7185235f6f2414219ce8c22abcc6b8886e6c30000000100000fbd
    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()`.

Title: Creating a Plugin (in Rust) - Part 2
Summary
This section describes the implementation details of the `SimplePluginCommand` for the `len` command. It details how the command's name, description, and signature are defined, along with the `run` method which receives a `Value`, checks if it's a string, and returns its length as an integer `Value`. Error handling is covered, showing how to create labeled errors with spans to indicate the source of the problem. It explains that `Len` is defined as a unit struct, and the common practice is to define the commands in plugins this way. It also covers the implementation of the `Plugin` trait for the `LenPlugin` struct, detailing the implementation of the `version()` and `commands()` methods, which report the plugin's version and initialize the plugin's commands, respectively.