1mod evaluated_call;
13mod plugin_custom_value;
14mod protocol_info;
15
16#[cfg(test)]
17mod tests;
18
19#[doc(hidden)]
22pub mod test_util;
23
24use nu_protocol::{
25 BlockId, ByteStreamType, Config, DeclId, DynamicCompletionCallRef, DynamicSuggestion,
26 LabeledError, PipelineData, PipelineMetadata, PluginMetadata, PluginSignature, ShellError,
27 SignalAction, Span, Spanned, Value,
28 ast::{self, Operator},
29 casing::Casing,
30 engine::{ArgType, Closure},
31 ir::IrBlock,
32};
33use nu_utils::SharedCow;
34use serde::{Deserialize, Serialize};
35use std::{collections::HashMap, path::PathBuf};
36
37pub use evaluated_call::EvaluatedCall;
38pub use plugin_custom_value::PluginCustomValue;
39#[allow(unused_imports)] pub use protocol_info::{Feature, Protocol, ProtocolInfo};
41
42pub type StreamId = usize;
44
45pub type PluginCallId = usize;
47
48pub type EngineCallId = usize;
50
51#[derive(Serialize, Deserialize, Debug, Clone)]
55pub struct CallInfo<D> {
56 pub name: String,
58 pub call: EvaluatedCall,
60 pub input: D,
62}
63
64#[derive(Serialize, Deserialize, Debug, Clone)]
65pub enum GetCompletionArgType {
66 Flag(String),
67 Positional(usize),
68}
69
70impl<'a> From<GetCompletionArgType> for ArgType<'a> {
71 fn from(value: GetCompletionArgType) -> Self {
72 match value {
73 GetCompletionArgType::Flag(flag_name) => {
74 ArgType::Flag(std::borrow::Cow::from(flag_name))
75 }
76 GetCompletionArgType::Positional(idx) => ArgType::Positional(idx),
77 }
78 }
79}
80
81#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
84pub struct DynamicCompletionCall {
85 pub call: ast::Call,
87 pub strip: bool,
89 pub pos: usize,
91}
92
93impl From<&DynamicCompletionCallRef<'_>> for DynamicCompletionCall {
94 fn from(call: &DynamicCompletionCallRef<'_>) -> Self {
95 DynamicCompletionCall {
96 call: call.call.clone(),
97 strip: call.strip,
98 pos: call.pos,
99 }
100 }
101}
102
103#[derive(Serialize, Deserialize, Debug, Clone)]
105pub struct GetCompletionInfo {
106 pub name: String,
108 pub arg_type: GetCompletionArgType,
110 pub call: DynamicCompletionCall,
112}
113
114impl<D> CallInfo<D> {
115 pub fn map_data<T>(
117 self,
118 f: impl FnOnce(D) -> Result<T, ShellError>,
119 ) -> Result<CallInfo<T>, ShellError> {
120 Ok(CallInfo {
121 name: self.name,
122 call: self.call,
123 input: f(self.input)?,
124 })
125 }
126}
127
128#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
132pub enum PipelineDataHeader {
133 Empty,
135 Value(Value, Option<PipelineMetadata>),
137 ListStream(ListStreamInfo),
141 ByteStream(ByteStreamInfo),
145}
146
147impl PipelineDataHeader {
148 pub fn stream_id(&self) -> Option<StreamId> {
150 match self {
151 PipelineDataHeader::Empty => None,
152 PipelineDataHeader::Value(_, _) => None,
153 PipelineDataHeader::ListStream(info) => Some(info.id),
154 PipelineDataHeader::ByteStream(info) => Some(info.id),
155 }
156 }
157
158 pub fn value(value: Value) -> Self {
159 PipelineDataHeader::Value(value, None)
160 }
161
162 pub fn list_stream(info: ListStreamInfo) -> Self {
163 PipelineDataHeader::ListStream(info)
164 }
165
166 pub fn byte_stream(info: ByteStreamInfo) -> Self {
167 PipelineDataHeader::ByteStream(info)
168 }
169}
170
171#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
173pub struct ListStreamInfo {
174 pub id: StreamId,
175 pub span: Span,
176 pub metadata: Option<PipelineMetadata>,
177}
178
179impl ListStreamInfo {
180 pub fn new(id: StreamId, span: Span) -> Self {
182 ListStreamInfo {
183 id,
184 span,
185 metadata: None,
186 }
187 }
188}
189
190#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
192pub struct ByteStreamInfo {
193 pub id: StreamId,
194 pub span: Span,
195 #[serde(rename = "type")]
196 pub type_: ByteStreamType,
197 pub metadata: Option<PipelineMetadata>,
198}
199
200impl ByteStreamInfo {
201 pub fn new(id: StreamId, span: Span, type_: ByteStreamType) -> Self {
203 ByteStreamInfo {
204 id,
205 span,
206 type_,
207 metadata: None,
208 }
209 }
210}
211
212#[derive(Serialize, Deserialize, Debug, Clone)]
214pub enum PluginCall<D> {
215 Metadata,
216 Signature,
217 Run(CallInfo<D>),
218 GetCompletion(GetCompletionInfo),
219 CustomValueOp(Spanned<PluginCustomValue>, CustomValueOp),
220}
221
222impl<D> PluginCall<D> {
223 pub fn map_data<T>(
226 self,
227 f: impl FnOnce(D) -> Result<T, ShellError>,
228 ) -> Result<PluginCall<T>, ShellError> {
229 Ok(match self {
230 PluginCall::Metadata => PluginCall::Metadata,
231 PluginCall::Signature => PluginCall::Signature,
232 PluginCall::GetCompletion(flag_name) => PluginCall::GetCompletion(flag_name),
233 PluginCall::Run(call) => PluginCall::Run(call.map_data(f)?),
234 PluginCall::CustomValueOp(custom_value, op) => {
235 PluginCall::CustomValueOp(custom_value, op)
236 }
237 })
238 }
239
240 pub fn span(&self) -> Option<Span> {
242 match self {
243 PluginCall::Metadata => None,
244 PluginCall::Signature => None,
245 PluginCall::GetCompletion(_) => None,
246 PluginCall::Run(CallInfo { call, .. }) => Some(call.head),
247 PluginCall::CustomValueOp(val, _) => Some(val.span),
248 }
249 }
250}
251
252#[derive(Serialize, Deserialize, Debug, Clone)]
254pub enum CustomValueOp {
255 ToBaseValue,
257 FollowPathInt {
259 index: Spanned<usize>,
260 optional: bool,
261 },
262 FollowPathString {
264 column_name: Spanned<String>,
265 optional: bool,
266 casing: Casing,
267 },
268 PartialCmp(Value),
270 Operation(Spanned<Operator>, Value),
272 Save {
274 path: Spanned<PathBuf>,
275 save_call_span: Span,
276 },
277 Dropped,
280}
281
282impl CustomValueOp {
283 pub fn name(&self) -> &'static str {
285 match self {
286 CustomValueOp::ToBaseValue => "to_base_value",
287 CustomValueOp::FollowPathInt { .. } => "follow_path_int",
288 CustomValueOp::FollowPathString { .. } => "follow_path_string",
289 CustomValueOp::PartialCmp(_) => "partial_cmp",
290 CustomValueOp::Operation(_, _) => "operation",
291 CustomValueOp::Save { .. } => "save",
292 CustomValueOp::Dropped => "dropped",
293 }
294 }
295}
296
297#[derive(Serialize, Deserialize, Debug, Clone)]
299pub enum PluginInput {
300 Hello(ProtocolInfo),
302 Call(PluginCallId, PluginCall<PipelineDataHeader>),
305 Goodbye,
308 EngineCallResponse(EngineCallId, EngineCallResponse<PipelineDataHeader>),
311 Data(StreamId, StreamData),
313 End(StreamId),
315 Drop(StreamId),
317 Ack(StreamId),
319 Signal(SignalAction),
321}
322
323impl TryFrom<PluginInput> for StreamMessage {
324 type Error = PluginInput;
325
326 fn try_from(msg: PluginInput) -> Result<StreamMessage, PluginInput> {
327 match msg {
328 PluginInput::Data(id, data) => Ok(StreamMessage::Data(id, data)),
329 PluginInput::End(id) => Ok(StreamMessage::End(id)),
330 PluginInput::Drop(id) => Ok(StreamMessage::Drop(id)),
331 PluginInput::Ack(id) => Ok(StreamMessage::Ack(id)),
332 _ => Err(msg),
333 }
334 }
335}
336
337impl From<StreamMessage> for PluginInput {
338 fn from(stream_msg: StreamMessage) -> PluginInput {
339 match stream_msg {
340 StreamMessage::Data(id, data) => PluginInput::Data(id, data),
341 StreamMessage::End(id) => PluginInput::End(id),
342 StreamMessage::Drop(id) => PluginInput::Drop(id),
343 StreamMessage::Ack(id) => PluginInput::Ack(id),
344 }
345 }
346}
347
348#[derive(Serialize, Deserialize, Debug, Clone)]
350pub enum StreamData {
351 List(Value),
352 Raw(Result<Vec<u8>, LabeledError>),
353}
354
355impl From<Value> for StreamData {
356 fn from(value: Value) -> Self {
357 StreamData::List(value)
358 }
359}
360
361impl From<Result<Vec<u8>, LabeledError>> for StreamData {
362 fn from(value: Result<Vec<u8>, LabeledError>) -> Self {
363 StreamData::Raw(value)
364 }
365}
366
367impl From<Result<Vec<u8>, ShellError>> for StreamData {
368 fn from(value: Result<Vec<u8>, ShellError>) -> Self {
369 value.map_err(LabeledError::from).into()
370 }
371}
372
373impl TryFrom<StreamData> for Value {
374 type Error = ShellError;
375
376 fn try_from(data: StreamData) -> Result<Value, ShellError> {
377 match data {
378 StreamData::List(value) => Ok(value),
379 StreamData::Raw(_) => Err(ShellError::PluginFailedToDecode {
380 msg: "expected list stream data, found raw data".into(),
381 }),
382 }
383 }
384}
385
386impl TryFrom<StreamData> for Result<Vec<u8>, LabeledError> {
387 type Error = ShellError;
388
389 fn try_from(data: StreamData) -> Result<Result<Vec<u8>, LabeledError>, ShellError> {
390 match data {
391 StreamData::Raw(value) => Ok(value),
392 StreamData::List(_) => Err(ShellError::PluginFailedToDecode {
393 msg: "expected raw stream data, found list data".into(),
394 }),
395 }
396 }
397}
398
399impl TryFrom<StreamData> for Result<Vec<u8>, ShellError> {
400 type Error = ShellError;
401
402 fn try_from(value: StreamData) -> Result<Result<Vec<u8>, ShellError>, ShellError> {
403 Result::<Vec<u8>, LabeledError>::try_from(value).map(|res| res.map_err(ShellError::from))
404 }
405}
406
407#[derive(Serialize, Deserialize, Debug, Clone)]
409pub enum StreamMessage {
410 Data(StreamId, StreamData),
412 End(StreamId),
414 Drop(StreamId),
417 Ack(StreamId),
420}
421
422#[derive(Serialize, Deserialize, Debug, Clone)]
424pub enum PluginCallResponse<D> {
425 Ok,
426 Error(ShellError),
427 Metadata(PluginMetadata),
428 Signature(Vec<PluginSignature>),
429 Ordering(Option<Ordering>),
430 CompletionItems(Option<Vec<DynamicSuggestion>>),
431 PipelineData(D),
432}
433
434impl<D> PluginCallResponse<D> {
435 pub fn map_data<T>(
438 self,
439 f: impl FnOnce(D) -> Result<T, ShellError>,
440 ) -> Result<PluginCallResponse<T>, ShellError> {
441 Ok(match self {
442 PluginCallResponse::Ok => PluginCallResponse::Ok,
443 PluginCallResponse::Error(err) => PluginCallResponse::Error(err),
444 PluginCallResponse::Metadata(meta) => PluginCallResponse::Metadata(meta),
445 PluginCallResponse::Signature(sigs) => PluginCallResponse::Signature(sigs),
446 PluginCallResponse::Ordering(ordering) => PluginCallResponse::Ordering(ordering),
447 PluginCallResponse::CompletionItems(items) => {
448 PluginCallResponse::CompletionItems(items)
449 }
450 PluginCallResponse::PipelineData(input) => PluginCallResponse::PipelineData(f(input)?),
451 })
452 }
453}
454
455impl PluginCallResponse<PipelineDataHeader> {
456 pub fn value(value: Value) -> PluginCallResponse<PipelineDataHeader> {
458 if value.is_nothing() {
459 PluginCallResponse::PipelineData(PipelineDataHeader::Empty)
460 } else {
461 PluginCallResponse::PipelineData(PipelineDataHeader::value(value))
462 }
463 }
464}
465
466impl PluginCallResponse<PipelineData> {
467 pub fn has_stream(&self) -> bool {
469 match self {
470 PluginCallResponse::PipelineData(data) => match data {
471 PipelineData::Empty => false,
472 PipelineData::Value(..) => false,
473 PipelineData::ListStream(..) => true,
474 PipelineData::ByteStream(..) => true,
475 },
476 _ => false,
477 }
478 }
479}
480
481#[derive(Serialize, Deserialize, Debug, Clone)]
483pub enum PluginOption {
484 GcDisabled(bool),
489}
490
491#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
493pub enum Ordering {
494 Less,
495 Equal,
496 Greater,
497}
498
499impl From<std::cmp::Ordering> for Ordering {
500 fn from(value: std::cmp::Ordering) -> Self {
501 match value {
502 std::cmp::Ordering::Less => Ordering::Less,
503 std::cmp::Ordering::Equal => Ordering::Equal,
504 std::cmp::Ordering::Greater => Ordering::Greater,
505 }
506 }
507}
508
509impl From<Ordering> for std::cmp::Ordering {
510 fn from(value: Ordering) -> Self {
511 match value {
512 Ordering::Less => std::cmp::Ordering::Less,
513 Ordering::Equal => std::cmp::Ordering::Equal,
514 Ordering::Greater => std::cmp::Ordering::Greater,
515 }
516 }
517}
518
519#[derive(Serialize, Deserialize, Debug, Clone)]
521pub enum PluginOutput {
522 Hello(ProtocolInfo),
524 Option(PluginOption),
526 CallResponse(PluginCallId, PluginCallResponse<PipelineDataHeader>),
529 EngineCall {
532 context: PluginCallId,
534 id: EngineCallId,
536 call: EngineCall<PipelineDataHeader>,
537 },
538 Data(StreamId, StreamData),
540 End(StreamId),
542 Drop(StreamId),
544 Ack(StreamId),
546}
547
548impl TryFrom<PluginOutput> for StreamMessage {
549 type Error = PluginOutput;
550
551 fn try_from(msg: PluginOutput) -> Result<StreamMessage, PluginOutput> {
552 match msg {
553 PluginOutput::Data(id, data) => Ok(StreamMessage::Data(id, data)),
554 PluginOutput::End(id) => Ok(StreamMessage::End(id)),
555 PluginOutput::Drop(id) => Ok(StreamMessage::Drop(id)),
556 PluginOutput::Ack(id) => Ok(StreamMessage::Ack(id)),
557 _ => Err(msg),
558 }
559 }
560}
561
562impl From<StreamMessage> for PluginOutput {
563 fn from(stream_msg: StreamMessage) -> PluginOutput {
564 match stream_msg {
565 StreamMessage::Data(id, data) => PluginOutput::Data(id, data),
566 StreamMessage::End(id) => PluginOutput::End(id),
567 StreamMessage::Drop(id) => PluginOutput::Drop(id),
568 StreamMessage::Ack(id) => PluginOutput::Ack(id),
569 }
570 }
571}
572
573#[derive(Serialize, Deserialize, Debug, Clone)]
577pub enum EngineCall<D> {
578 GetConfig,
580 GetPluginConfig,
582 GetEnvVar(String),
584 GetEnvVars,
586 GetCurrentDir,
588 AddEnvVar(String, Value),
590 GetHelp,
592 EnterForeground,
594 LeaveForeground,
596 GetSpanContents(Span),
598 EvalClosure {
600 closure: Spanned<Closure>,
604 positional: Vec<Value>,
606 input: D,
608 redirect_stdout: bool,
610 redirect_stderr: bool,
612 },
613 FindDecl(String),
615 GetBlockIR(BlockId),
617 CallDecl {
619 decl_id: DeclId,
621 call: EvaluatedCall,
623 input: D,
625 redirect_stdout: bool,
627 redirect_stderr: bool,
629 },
630}
631
632impl<D> EngineCall<D> {
633 pub fn name(&self) -> &'static str {
635 match self {
636 EngineCall::GetConfig => "GetConfig",
637 EngineCall::GetPluginConfig => "GetPluginConfig",
638 EngineCall::GetEnvVar(_) => "GetEnv",
639 EngineCall::GetEnvVars => "GetEnvs",
640 EngineCall::GetCurrentDir => "GetCurrentDir",
641 EngineCall::AddEnvVar(..) => "AddEnvVar",
642 EngineCall::GetHelp => "GetHelp",
643 EngineCall::EnterForeground => "EnterForeground",
644 EngineCall::LeaveForeground => "LeaveForeground",
645 EngineCall::GetSpanContents(_) => "GetSpanContents",
646 EngineCall::EvalClosure { .. } => "EvalClosure",
647 EngineCall::FindDecl(_) => "FindDecl",
648 EngineCall::GetBlockIR(_) => "GetBlockIR",
649 EngineCall::CallDecl { .. } => "CallDecl",
650 }
651 }
652
653 pub fn map_data<T>(
656 self,
657 f: impl FnOnce(D) -> Result<T, ShellError>,
658 ) -> Result<EngineCall<T>, ShellError> {
659 Ok(match self {
660 EngineCall::GetConfig => EngineCall::GetConfig,
661 EngineCall::GetPluginConfig => EngineCall::GetPluginConfig,
662 EngineCall::GetEnvVar(name) => EngineCall::GetEnvVar(name),
663 EngineCall::GetEnvVars => EngineCall::GetEnvVars,
664 EngineCall::GetCurrentDir => EngineCall::GetCurrentDir,
665 EngineCall::AddEnvVar(name, value) => EngineCall::AddEnvVar(name, value),
666 EngineCall::GetHelp => EngineCall::GetHelp,
667 EngineCall::EnterForeground => EngineCall::EnterForeground,
668 EngineCall::LeaveForeground => EngineCall::LeaveForeground,
669 EngineCall::GetSpanContents(span) => EngineCall::GetSpanContents(span),
670 EngineCall::EvalClosure {
671 closure,
672 positional,
673 input,
674 redirect_stdout,
675 redirect_stderr,
676 } => EngineCall::EvalClosure {
677 closure,
678 positional,
679 input: f(input)?,
680 redirect_stdout,
681 redirect_stderr,
682 },
683 EngineCall::FindDecl(name) => EngineCall::FindDecl(name),
684 EngineCall::GetBlockIR(block_id) => EngineCall::GetBlockIR(block_id),
685 EngineCall::CallDecl {
686 decl_id,
687 call,
688 input,
689 redirect_stdout,
690 redirect_stderr,
691 } => EngineCall::CallDecl {
692 decl_id,
693 call,
694 input: f(input)?,
695 redirect_stdout,
696 redirect_stderr,
697 },
698 })
699 }
700}
701
702#[derive(Serialize, Deserialize, Debug, Clone)]
705pub enum EngineCallResponse<D> {
706 Error(ShellError),
707 PipelineData(D),
708 Config(SharedCow<Config>),
709 ValueMap(HashMap<String, Value>),
710 Identifier(DeclId),
711 IrBlock(Box<IrBlock>),
712}
713
714impl<D> EngineCallResponse<D> {
715 pub fn map_data<T>(
718 self,
719 f: impl FnOnce(D) -> Result<T, ShellError>,
720 ) -> Result<EngineCallResponse<T>, ShellError> {
721 Ok(match self {
722 EngineCallResponse::Error(err) => EngineCallResponse::Error(err),
723 EngineCallResponse::PipelineData(data) => EngineCallResponse::PipelineData(f(data)?),
724 EngineCallResponse::Config(config) => EngineCallResponse::Config(config),
725 EngineCallResponse::ValueMap(map) => EngineCallResponse::ValueMap(map),
726 EngineCallResponse::Identifier(id) => EngineCallResponse::Identifier(id),
727 EngineCallResponse::IrBlock(ir) => EngineCallResponse::IrBlock(ir),
728 })
729 }
730}
731
732impl EngineCallResponse<PipelineData> {
733 pub fn value(value: Value) -> EngineCallResponse<PipelineData> {
735 EngineCallResponse::PipelineData(PipelineData::value(value, None))
736 }
737
738 pub const fn empty() -> EngineCallResponse<PipelineData> {
740 EngineCallResponse::PipelineData(PipelineData::empty())
741 }
742}