use nu_protocol::{
Example, IntoSpanned, LabeledError, PipelineData, PluginExample, PluginSignature, ShellError,
Signature, Value,
};
use crate::{EngineInterface, EvaluatedCall, Plugin};
pub trait PluginCommand: Sync {
type Plugin: Plugin;
fn name(&self) -> &str;
fn signature(&self) -> Signature;
fn usage(&self) -> &str;
fn extra_usage(&self) -> &str {
""
}
fn search_terms(&self) -> Vec<&str> {
vec![]
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn run(
&self,
plugin: &Self::Plugin,
engine: &EngineInterface,
call: &EvaluatedCall,
input: PipelineData,
) -> Result<PipelineData, LabeledError>;
}
pub trait SimplePluginCommand: Sync {
type Plugin: Plugin;
fn name(&self) -> &str;
fn signature(&self) -> Signature;
fn usage(&self) -> &str;
fn extra_usage(&self) -> &str {
""
}
fn search_terms(&self) -> Vec<&str> {
vec![]
}
fn examples(&self) -> Vec<Example> {
vec![]
}
fn run(
&self,
plugin: &Self::Plugin,
engine: &EngineInterface,
call: &EvaluatedCall,
input: &Value,
) -> Result<Value, LabeledError>;
}
impl<T> PluginCommand for T
where
T: SimplePluginCommand,
{
type Plugin = <Self as SimplePluginCommand>::Plugin;
fn examples(&self) -> Vec<Example> {
<Self as SimplePluginCommand>::examples(self)
}
fn extra_usage(&self) -> &str {
<Self as SimplePluginCommand>::extra_usage(self)
}
fn name(&self) -> &str {
<Self as SimplePluginCommand>::name(self)
}
fn run(
&self,
plugin: &Self::Plugin,
engine: &EngineInterface,
call: &EvaluatedCall,
input: PipelineData,
) -> Result<PipelineData, LabeledError> {
let span = input.span().unwrap_or(call.head);
let input_value = input.into_value(span)?;
<Self as SimplePluginCommand>::run(self, plugin, engine, call, &input_value)
.map(|value| PipelineData::Value(value, None))
}
fn search_terms(&self) -> Vec<&str> {
<Self as SimplePluginCommand>::search_terms(self)
}
fn signature(&self) -> Signature {
<Self as SimplePluginCommand>::signature(self)
}
fn usage(&self) -> &str {
<Self as SimplePluginCommand>::usage(self)
}
}
#[doc(hidden)]
pub fn create_plugin_signature(command: &(impl PluginCommand + ?Sized)) -> PluginSignature {
PluginSignature::new(
command
.signature()
.usage(command.usage())
.extra_usage(command.extra_usage())
.search_terms(
command
.search_terms()
.into_iter()
.map(String::from)
.collect(),
),
command
.examples()
.into_iter()
.map(PluginExample::from)
.collect(),
)
}
pub(crate) fn render_examples(
plugin: &impl Plugin,
engine: &EngineInterface,
examples: &mut [PluginExample],
) -> Result<(), ShellError> {
for example in examples {
if let Some(ref mut value) = example.result {
value.recurse_mut(&mut |value| {
let span = value.span();
match value {
Value::Custom { .. } => {
let value_taken = std::mem::replace(value, Value::nothing(span));
let Value::Custom { val, .. } = value_taken else {
unreachable!()
};
*value =
plugin.custom_value_to_base_value(engine, val.into_spanned(span))?;
Ok::<_, ShellError>(())
}
_ => Ok(()),
}
})?;
}
}
Ok(())
}