Home Explore Blog CI



nushell

12th chunk of `contributor-book/plugins.md`
004988848e28ac47b13e62c61ae19ca20986d011dc30ff4e0000000100000fba
    let result = PluginTest::new("fib", FibPlugin.into())?
        .add_decl(Box::new(Seq))?
        .eval("seq 1 10 | fib")?;

    assert_eq!(10, result.into_iter().count());
}
```

Keep in mind that this will increase the compilation time of your tests, so it's generally preferred to do your other test logic within Rust if you can.

Tests on custom values are fully supported as well, but they will be serialized and deserialized to ensure that they are able to pass through the serialization that happens to custom values between the plugin and the engine safely.

## Under the hood

Writing Nu plugins in Rust is convenient because we can make use of the `nu-plugin` and `nu-protocol` crates, which are part of Nu itself and define the interface protocol. To write a plugin in another language you will need to implement that protocol yourself. If you're goal is to write Nu plugins in Rust you can stop here. If you'd like to explore the low level plugin interface or write plugins in other languages such as Python, keep reading.

Ordinarily, Nu will execute the plugin and knows what data to pass to it and how to interpret the responses. Here we'll be doing it manually. Note that we'll be playing with our plugin using a conventional shell (like bash or zsh) as in Nu all of this happens under the hood.

We recommend keeping the [plugin protocol](plugin_protocol_reference.md) documentation handy as a reference while reading this section.

Assuming you've built the Rust plugin described above let's now run it with `--stdio` so that it communicates with us there:

```sh
$ ./target/release/nu_plugin_len --stdio
json
```

The application on start up prints the keyword `json` and blocks for input on STDIN. This tells Nu that the plugin wants to communicate via the JSON protocol rather than MsgPack. In the JSON protocol, the plugin will listen for each JSON object written on stdin and respond accordingly. Newlines are not required, but it is likely that the plugin will not see your input before you hit `enter`, as terminals usually line buffer by default.

We can simulate an initial plugin registration by sending a [`Hello`](plugin_protocol_reference.md#hello) message first, in order to let the plugin know that we are compatible with it. It is important to use the version of `nu-plugin` that the plugin was built with here for the `"version"` as this is a critical part of how Nu ensures that plugins run with a compatible engine.

```json
{
  "Hello": {
    "protocol": "nu-plugin",
    "version": "0.90.2",
    "features": []
  }
}
```

After that, we send a [`Signature`](plugin_protocol_reference.md#signature-plugin-call) call to the plugin with ID `0`:

```json
{
  "Call": [0, "Signature"]
}
```

Putting that together, it looks like this:

```sh
$ ./target/release/nu_plugin_len --stdio
json{"Hello":{"protocol":"nu-plugin","version":"0.90.2","features":[]}}
{"Hello":{"protocol":"nu-plugin","version":"0.90.2","features":[]}}
{"Call":[0,"Signature"]}
{"CallResponse":[0, {"Signature":[{"sig":{"name":"len","description":"calculates the length of its input","extra_description":"","search_terms":[],"required_positional":[],"optional_positional":[],"rest_positional":null,"vectorizes_over_list":false,"named":[{"long":"help","short":"h","arg":null,"required":false,"desc":"Display the help message for this command","var_id":null,"default_value":null}],"input_type":"String","output_type":"Int","input_output_types":[],"allow_variants_without_examples":false,"is_filter":false,"creates_scope":false,"allows_unknown_args":false,"category":"Default"},"examples":[]}]}]}
```

The plugin prints its signature serialized as JSON. We'll reformat for readability.

```json
{
  "Signature": [
    {
      "sig": {
        "name": "len",
        "description": "calculates the length of its input",
        "extra_description": "",
        "search_terms": [],
        "required_positional": [],
        "optional_positional": [],
        "rest_positional": null,
        "vectorizes_over_list": false,

Title: Under the Hood: Plugin Mechanics and Manual Interaction
Summary
This section delves into the underlying mechanics of Nu plugins, describing how they interact with the engine using the JSON protocol. It explains how to manually interact with a plugin using a conventional shell, simulating the communication that normally occurs under the hood in Nu. The process starts by running the plugin with `--stdio` to enable JSON communication. Then, `Hello` and `Signature` messages are manually sent to the plugin to get its signature and initiate a plugin call. The section also states the importance of using the same version of `nu-plugin` to ensure compatibility between Nu and the plugin.