nu_plugin_engine/
declaration.rs1use nu_engine::{command_prelude::*, get_eval_expression};
2use nu_plugin_protocol::{
3 CallInfo, DynamicCompletionCall, EvaluatedCall, GetCompletionArgType, GetCompletionInfo,
4};
5use nu_protocol::engine::ArgType;
6use nu_protocol::{DynamicCompletionCallRef, DynamicSuggestion};
7use nu_protocol::{PluginIdentity, PluginSignature, engine::CommandType};
8use std::sync::Arc;
9
10use crate::{GetPlugin, PluginExecutionCommandContext, PluginSource};
11
12#[derive(Clone)]
14pub struct PluginDeclaration {
15 name: String,
16 signature: PluginSignature,
17 source: PluginSource,
18}
19
20impl PluginDeclaration {
21 pub fn new(plugin: Arc<dyn GetPlugin>, signature: PluginSignature) -> Self {
22 Self {
23 name: signature.sig.name.clone(),
24 signature,
25 source: PluginSource::new(plugin),
26 }
27 }
28}
29
30impl Command for PluginDeclaration {
31 fn name(&self) -> &str {
32 &self.name
33 }
34
35 fn signature(&self) -> Signature {
36 self.signature.sig.clone()
37 }
38
39 fn description(&self) -> &str {
40 self.signature.sig.description.as_str()
41 }
42
43 fn extra_description(&self) -> &str {
44 self.signature.sig.extra_description.as_str()
45 }
46
47 fn search_terms(&self) -> Vec<&str> {
48 self.signature
49 .sig
50 .search_terms
51 .iter()
52 .map(|term| term.as_str())
53 .collect()
54 }
55
56 fn examples(&self) -> Vec<Example<'_>> {
57 let mut res = vec![];
58 for e in self.signature.examples.iter() {
59 res.push(Example {
60 example: &e.example,
61 description: &e.description,
62 result: e.result.clone(),
63 })
64 }
65 res
66 }
67
68 fn run(
69 &self,
70 engine_state: &EngineState,
71 stack: &mut Stack,
72 call: &Call,
73 input: PipelineData,
74 ) -> Result<PipelineData, ShellError> {
75 let eval_expression = get_eval_expression(engine_state);
76
77 let evaluated_call =
80 EvaluatedCall::try_from_call(call, engine_state, stack, eval_expression)?;
81
82 let engine_config = stack.get_config(engine_state);
84
85 let plugin = self
87 .source
88 .persistent(None)
89 .and_then(|p| {
90 p.set_gc_config(engine_config.plugin_gc.get(p.identity().name()));
92 p.get_plugin(Some((engine_state, stack)))
93 })
94 .map_err(|err| {
95 let decl = engine_state.get_decl(call.decl_id);
96 ShellError::GenericError {
97 error: format!("Unable to spawn plugin for `{}`", decl.name()),
98 msg: err.to_string(),
99 span: Some(call.head),
100 help: None,
101 inner: vec![],
102 }
103 })?;
104
105 let mut context = PluginExecutionCommandContext::new(
107 self.source.identity.clone(),
108 engine_state,
109 stack,
110 call,
111 );
112
113 plugin.run(
114 CallInfo {
115 name: self.name.clone(),
116 call: evaluated_call,
117 input,
118 },
119 &mut context,
120 )
121 }
122
123 fn command_type(&self) -> CommandType {
124 CommandType::Plugin
125 }
126
127 fn plugin_identity(&self) -> Option<&PluginIdentity> {
128 Some(&self.source.identity)
129 }
130
131 #[expect(deprecated, reason = "internal usage")]
132 fn get_dynamic_completion(
133 &self,
134 engine_state: &EngineState,
135 stack: &mut Stack,
136 call: DynamicCompletionCallRef,
137 arg_type: &ArgType,
138 _experimental: nu_protocol::engine::ExperimentalMarker,
139 ) -> Result<Option<Vec<DynamicSuggestion>>, ShellError> {
140 let engine_config = stack.get_config(engine_state);
142
143 let plugin = self
145 .source
146 .persistent(None)
147 .and_then(|p| {
148 p.set_gc_config(engine_config.plugin_gc.get(p.identity().name()));
150 p.get_plugin(Some((engine_state, stack)))
151 })
152 .map_err(|err| ShellError::GenericError {
153 error: "failed to get custom completion".to_string(),
154 msg: err.to_string(),
155 span: None,
156 help: None,
157 inner: vec![],
158 })?;
159
160 let arg_info = match arg_type {
161 ArgType::Flag(flag_name) => GetCompletionArgType::Flag(flag_name.to_string()),
162 ArgType::Positional(index) => GetCompletionArgType::Positional(*index),
163 };
164 plugin.get_dynamic_completion(GetCompletionInfo {
165 name: self.name.clone(),
166 arg_type: arg_info,
167 call: DynamicCompletionCall {
168 call: call.call.clone(),
169 strip: call.strip,
170 pos: call.pos,
171 },
172 })
173 }
174}