use nu_protocol::{
DynamicSuggestion, Example, IntoSpanned, LabeledError, PipelineData, PluginExample,
PluginSignature, ShellError, Signature, Value, engine::ArgType,
};
use crate::{DynamicCompletionCall, EngineInterface, EvaluatedCall, Plugin};
pub trait PluginCommand: Sync {
type Plugin: Plugin;
fn name(&self) -> &str;
fn signature(&self) -> Signature;
fn description(&self) -> &str;
fn extra_description(&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>;
#[allow(unused_variables)]
#[expect(deprecated, reason = "forwarding experimental status")]
fn get_dynamic_completion(
&self,
plugin: &Self::Plugin,
engine: &EngineInterface,
call: DynamicCompletionCall,
arg_type: ArgType,
_experimental: nu_protocol::engine::ExperimentalMarker,
) -> Option<Vec<DynamicSuggestion>> {
None
}
}
pub trait SimplePluginCommand: Sync {
type Plugin: Plugin;
fn name(&self) -> &str;
fn signature(&self) -> Signature;
fn description(&self) -> &str;
fn extra_description(&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>;
#[allow(unused_variables)]
#[expect(deprecated, reason = "forwarding experimental status")]
fn get_dynamic_completion(
&self,
plugin: &Self::Plugin,
engine: &EngineInterface,
call: DynamicCompletionCall,
arg_type: ArgType,
_experimental: nu_protocol::engine::ExperimentalMarker,
) -> Option<Vec<DynamicSuggestion>> {
None
}
}
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_description(&self) -> &str {
<Self as SimplePluginCommand>::extra_description(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 description(&self) -> &str {
<Self as SimplePluginCommand>::description(self)
}
#[allow(unused_variables)]
#[allow(deprecated, reason = "internal usage")]
fn get_dynamic_completion(
&self,
plugin: &Self::Plugin,
engine: &EngineInterface,
call: DynamicCompletionCall,
arg_type: ArgType,
experimental: nu_protocol::engine::ExperimentalMarker,
) -> Option<Vec<DynamicSuggestion>> {
<Self as SimplePluginCommand>::get_dynamic_completion(
self,
plugin,
engine,
call,
arg_type,
experimental,
)
}
}
#[doc(hidden)]
pub fn create_plugin_signature(command: &(impl PluginCommand + ?Sized)) -> PluginSignature {
PluginSignature::new(
command
.signature()
.description(command.description())
.extra_description(command.extra_description())
.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(())
}