nu_plugin_engine/
declaration.rs1use nu_engine::{command_prelude::*, get_eval_expression};
2use nu_plugin_protocol::{CallInfo, EvaluatedCall, GetCompletionArgType, GetCompletionInfo};
3use nu_protocol::engine::ArgType;
4use nu_protocol::shell_error::generic::GenericError;
5use nu_protocol::{DynamicCompletionCallRef, DynamicSuggestion};
6use nu_protocol::{PluginIdentity, PluginSignature, engine::CommandType};
7use std::sync::Arc;
8
9use crate::context::PluginGetDynamicCompletionContext;
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::Generic(GenericError::new(
97 format!("Unable to spawn plugin for `{}`", decl.name()),
98 err.to_string(),
99 call.head,
100 ))
101 })?;
102
103 let mut context = PluginExecutionCommandContext::new(
105 self.source.identity.clone(),
106 engine_state,
107 stack,
108 call,
109 );
110
111 plugin.run(
112 CallInfo {
113 name: self.name.clone(),
114 call: evaluated_call,
115 input,
116 },
117 &mut context,
118 )
119 }
120
121 fn command_type(&self) -> CommandType {
122 CommandType::Plugin
123 }
124
125 fn plugin_identity(&self) -> Option<&PluginIdentity> {
126 Some(&self.source.identity)
127 }
128
129 #[expect(deprecated, reason = "internal usage")]
130 fn get_dynamic_completion(
131 &self,
132 engine_state: &EngineState,
133 stack: &mut Stack,
134 call: DynamicCompletionCallRef,
135 arg_type: &ArgType,
136 _experimental: nu_protocol::engine::ExperimentalMarker,
137 ) -> Result<Option<Vec<DynamicSuggestion>>, ShellError> {
138 let engine_config = stack.get_config(engine_state);
140
141 let plugin = self
143 .source
144 .persistent(None)
145 .and_then(|p| {
146 p.set_gc_config(engine_config.plugin_gc.get(p.identity().name()));
148 p.get_plugin(Some((engine_state, stack)))
149 })
150 .map_err(|err| {
151 ShellError::Generic(GenericError::new_internal(
152 "failed to get custom completion",
153 err.to_string(),
154 ))
155 })?;
156
157 let arg_info = match arg_type {
158 ArgType::Flag(flag_name) => GetCompletionArgType::Flag(flag_name.to_string()),
159 ArgType::Positional(index) => GetCompletionArgType::Positional(*index),
160 };
161
162 let mut context = PluginGetDynamicCompletionContext::new(
163 self.source.identity.clone(),
164 engine_state,
165 stack,
166 &call,
167 );
168
169 plugin.get_dynamic_completion(
170 GetCompletionInfo {
171 name: self.name.clone(),
172 arg_type: arg_info,
173 call: (&call).into(),
174 },
175 &mut context,
176 )
177 }
178}