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()
)
},
PipelineData::Value(Value::String { val, .. }, _) => {
Ok(Value::int(val.len() as i64, call.head).into_pipeline_data())
},
_ => Err(
LabeledError::new(
"Expected String or iterable input from pipeline",
).with_label(
format!(
"requires string or iterable input; got {}",
input.get_type(),
),
call.head,
)
),
}
}
}
```
With this change, we can pipe a list (even a long one) to the command to get its length:
```nu
$ seq 1 10000 | len
10000
```
Since `run()` also returns `PipelineData`, it is also possible for the plugin to produce a stream, or even to transform a stream. For example, if we wanted our plugin to multiply every integer by
two:
```rust
fn run(
...,
engine: &EngineInterface,
call: &EvaluatedCall,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
input.map(|value| {
let span = value.span();
match value.as_int() {
Ok(int) => Value::int(int * 2, span),
// In list streams (i.e., lists of `Value`), errors are always represented by
// `Value::Error`.
Err(err) => Value::error(err, span),
}
}, engine.signals()).map_err(|e|
LabeledError::new(
"Failed",
).with_label(
format!(
"Failed; {}",
e,
),
call.head,
)
)
}
```
Since the input and output are both streaming, this will work even on an infinite stream:
```nu
$ generate { |n| {out: $n, next: ($n + 1)} } 0 | plugin
0
2
4
6
8
# ...
```
## Plugin configuration
It is possible for a user to provide configuration to a plugin. For a plugin named `motd`:
```nu
$env.config.plugins = {
motd: {
message: "Nushell rocks!"
}
}
```
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,