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, DynamicSuggestion, LabeledError, PipelineData,
26 PipelineMetadata, PluginMetadata, PluginSignature, ShellError, SignalAction, Span, Spanned,
27 Value, ast,
28 ast::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
93#[derive(Serialize, Deserialize, Debug, Clone)]
95pub struct GetCompletionInfo {
96 pub name: String,
98 pub arg_type: GetCompletionArgType,
100 pub call: DynamicCompletionCall,
102}
103
104impl<D> CallInfo<D> {
105 pub fn map_data<T>(
107 self,
108 f: impl FnOnce(D) -> Result<T, ShellError>,
109 ) -> Result<CallInfo<T>, ShellError> {
110 Ok(CallInfo {
111 name: self.name,
112 call: self.call,
113 input: f(self.input)?,
114 })
115 }
116}
117
118#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
122pub enum PipelineDataHeader {
123 Empty,
125 Value(Value, Option<PipelineMetadata>),
127 ListStream(ListStreamInfo),
131 ByteStream(ByteStreamInfo),
135}
136
137impl PipelineDataHeader {
138 pub fn stream_id(&self) -> Option<StreamId> {
140 match self {
141 PipelineDataHeader::Empty => None,
142 PipelineDataHeader::Value(_, _) => None,
143 PipelineDataHeader::ListStream(info) => Some(info.id),
144 PipelineDataHeader::ByteStream(info) => Some(info.id),
145 }
146 }
147
148 pub fn value(value: Value) -> Self {
149 PipelineDataHeader::Value(value, None)
150 }
151
152 pub fn list_stream(info: ListStreamInfo) -> Self {
153 PipelineDataHeader::ListStream(info)
154 }
155
156 pub fn byte_stream(info: ByteStreamInfo) -> Self {
157 PipelineDataHeader::ByteStream(info)
158 }
159}
160
161#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
163pub struct ListStreamInfo {
164 pub id: StreamId,
165 pub span: Span,
166 pub metadata: Option<PipelineMetadata>,
167}
168
169impl ListStreamInfo {
170 pub fn new(id: StreamId, span: Span) -> Self {
172 ListStreamInfo {
173 id,
174 span,
175 metadata: None,
176 }
177 }
178}
179
180#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
182pub struct ByteStreamInfo {
183 pub id: StreamId,
184 pub span: Span,
185 #[serde(rename = "type")]
186 pub type_: ByteStreamType,
187 pub metadata: Option<PipelineMetadata>,
188}
189
190impl ByteStreamInfo {
191 pub fn new(id: StreamId, span: Span, type_: ByteStreamType) -> Self {
193 ByteStreamInfo {
194 id,
195 span,
196 type_,
197 metadata: None,
198 }
199 }
200}
201
202#[derive(Serialize, Deserialize, Debug, Clone)]
204pub enum PluginCall<D> {
205 Metadata,
206 Signature,
207 Run(CallInfo<D>),
208 GetCompletion(GetCompletionInfo),
209 CustomValueOp(Spanned<PluginCustomValue>, CustomValueOp),
210}
211
212impl<D> PluginCall<D> {
213 pub fn map_data<T>(
216 self,
217 f: impl FnOnce(D) -> Result<T, ShellError>,
218 ) -> Result<PluginCall<T>, ShellError> {
219 Ok(match self {
220 PluginCall::Metadata => PluginCall::Metadata,
221 PluginCall::Signature => PluginCall::Signature,
222 PluginCall::GetCompletion(flag_name) => PluginCall::GetCompletion(flag_name),
223 PluginCall::Run(call) => PluginCall::Run(call.map_data(f)?),
224 PluginCall::CustomValueOp(custom_value, op) => {
225 PluginCall::CustomValueOp(custom_value, op)
226 }
227 })
228 }
229
230 pub fn span(&self) -> Option<Span> {
232 match self {
233 PluginCall::Metadata => None,
234 PluginCall::Signature => None,
235 PluginCall::GetCompletion(_) => None,
236 PluginCall::Run(CallInfo { call, .. }) => Some(call.head),
237 PluginCall::CustomValueOp(val, _) => Some(val.span),
238 }
239 }
240}
241
242#[derive(Serialize, Deserialize, Debug, Clone)]
244pub enum CustomValueOp {
245 ToBaseValue,
247 FollowPathInt {
249 index: Spanned<usize>,
250 optional: bool,
251 },
252 FollowPathString {
254 column_name: Spanned<String>,
255 optional: bool,
256 casing: Casing,
257 },
258 PartialCmp(Value),
260 Operation(Spanned<Operator>, Value),
262 Save {
264 path: Spanned<PathBuf>,
265 save_call_span: Span,
266 },
267 Dropped,
270}
271
272impl CustomValueOp {
273 pub fn name(&self) -> &'static str {
275 match self {
276 CustomValueOp::ToBaseValue => "to_base_value",
277 CustomValueOp::FollowPathInt { .. } => "follow_path_int",
278 CustomValueOp::FollowPathString { .. } => "follow_path_string",
279 CustomValueOp::PartialCmp(_) => "partial_cmp",
280 CustomValueOp::Operation(_, _) => "operation",
281 CustomValueOp::Save { .. } => "save",
282 CustomValueOp::Dropped => "dropped",
283 }
284 }
285}
286
287#[derive(Serialize, Deserialize, Debug, Clone)]
289pub enum PluginInput {
290 Hello(ProtocolInfo),
292 Call(PluginCallId, PluginCall<PipelineDataHeader>),
295 Goodbye,
298 EngineCallResponse(EngineCallId, EngineCallResponse<PipelineDataHeader>),
301 Data(StreamId, StreamData),
303 End(StreamId),
305 Drop(StreamId),
307 Ack(StreamId),
309 Signal(SignalAction),
311}
312
313impl TryFrom<PluginInput> for StreamMessage {
314 type Error = PluginInput;
315
316 fn try_from(msg: PluginInput) -> Result<StreamMessage, PluginInput> {
317 match msg {
318 PluginInput::Data(id, data) => Ok(StreamMessage::Data(id, data)),
319 PluginInput::End(id) => Ok(StreamMessage::End(id)),
320 PluginInput::Drop(id) => Ok(StreamMessage::Drop(id)),
321 PluginInput::Ack(id) => Ok(StreamMessage::Ack(id)),
322 _ => Err(msg),
323 }
324 }
325}
326
327impl From<StreamMessage> for PluginInput {
328 fn from(stream_msg: StreamMessage) -> PluginInput {
329 match stream_msg {
330 StreamMessage::Data(id, data) => PluginInput::Data(id, data),
331 StreamMessage::End(id) => PluginInput::End(id),
332 StreamMessage::Drop(id) => PluginInput::Drop(id),
333 StreamMessage::Ack(id) => PluginInput::Ack(id),
334 }
335 }
336}
337
338#[derive(Serialize, Deserialize, Debug, Clone)]
340pub enum StreamData {
341 List(Value),
342 Raw(Result<Vec<u8>, LabeledError>),
343}
344
345impl From<Value> for StreamData {
346 fn from(value: Value) -> Self {
347 StreamData::List(value)
348 }
349}
350
351impl From<Result<Vec<u8>, LabeledError>> for StreamData {
352 fn from(value: Result<Vec<u8>, LabeledError>) -> Self {
353 StreamData::Raw(value)
354 }
355}
356
357impl From<Result<Vec<u8>, ShellError>> for StreamData {
358 fn from(value: Result<Vec<u8>, ShellError>) -> Self {
359 value.map_err(LabeledError::from).into()
360 }
361}
362
363impl TryFrom<StreamData> for Value {
364 type Error = ShellError;
365
366 fn try_from(data: StreamData) -> Result<Value, ShellError> {
367 match data {
368 StreamData::List(value) => Ok(value),
369 StreamData::Raw(_) => Err(ShellError::PluginFailedToDecode {
370 msg: "expected list stream data, found raw data".into(),
371 }),
372 }
373 }
374}
375
376impl TryFrom<StreamData> for Result<Vec<u8>, LabeledError> {
377 type Error = ShellError;
378
379 fn try_from(data: StreamData) -> Result<Result<Vec<u8>, LabeledError>, ShellError> {
380 match data {
381 StreamData::Raw(value) => Ok(value),
382 StreamData::List(_) => Err(ShellError::PluginFailedToDecode {
383 msg: "expected raw stream data, found list data".into(),
384 }),
385 }
386 }
387}
388
389impl TryFrom<StreamData> for Result<Vec<u8>, ShellError> {
390 type Error = ShellError;
391
392 fn try_from(value: StreamData) -> Result<Result<Vec<u8>, ShellError>, ShellError> {
393 Result::<Vec<u8>, LabeledError>::try_from(value).map(|res| res.map_err(ShellError::from))
394 }
395}
396
397#[derive(Serialize, Deserialize, Debug, Clone)]
399pub enum StreamMessage {
400 Data(StreamId, StreamData),
402 End(StreamId),
404 Drop(StreamId),
407 Ack(StreamId),
410}
411
412#[derive(Serialize, Deserialize, Debug, Clone)]
414pub enum PluginCallResponse<D> {
415 Ok,
416 Error(ShellError),
417 Metadata(PluginMetadata),
418 Signature(Vec<PluginSignature>),
419 Ordering(Option<Ordering>),
420 CompletionItems(Option<Vec<DynamicSuggestion>>),
421 PipelineData(D),
422}
423
424impl<D> PluginCallResponse<D> {
425 pub fn map_data<T>(
428 self,
429 f: impl FnOnce(D) -> Result<T, ShellError>,
430 ) -> Result<PluginCallResponse<T>, ShellError> {
431 Ok(match self {
432 PluginCallResponse::Ok => PluginCallResponse::Ok,
433 PluginCallResponse::Error(err) => PluginCallResponse::Error(err),
434 PluginCallResponse::Metadata(meta) => PluginCallResponse::Metadata(meta),
435 PluginCallResponse::Signature(sigs) => PluginCallResponse::Signature(sigs),
436 PluginCallResponse::Ordering(ordering) => PluginCallResponse::Ordering(ordering),
437 PluginCallResponse::CompletionItems(items) => {
438 PluginCallResponse::CompletionItems(items)
439 }
440 PluginCallResponse::PipelineData(input) => PluginCallResponse::PipelineData(f(input)?),
441 })
442 }
443}
444
445impl PluginCallResponse<PipelineDataHeader> {
446 pub fn value(value: Value) -> PluginCallResponse<PipelineDataHeader> {
448 if value.is_nothing() {
449 PluginCallResponse::PipelineData(PipelineDataHeader::Empty)
450 } else {
451 PluginCallResponse::PipelineData(PipelineDataHeader::value(value))
452 }
453 }
454}
455
456impl PluginCallResponse<PipelineData> {
457 pub fn has_stream(&self) -> bool {
459 match self {
460 PluginCallResponse::PipelineData(data) => match data {
461 PipelineData::Empty => false,
462 PipelineData::Value(..) => false,
463 PipelineData::ListStream(..) => true,
464 PipelineData::ByteStream(..) => true,
465 },
466 _ => false,
467 }
468 }
469}
470
471#[derive(Serialize, Deserialize, Debug, Clone)]
473pub enum PluginOption {
474 GcDisabled(bool),
479}
480
481#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
483pub enum Ordering {
484 Less,
485 Equal,
486 Greater,
487}
488
489impl From<std::cmp::Ordering> for Ordering {
490 fn from(value: std::cmp::Ordering) -> Self {
491 match value {
492 std::cmp::Ordering::Less => Ordering::Less,
493 std::cmp::Ordering::Equal => Ordering::Equal,
494 std::cmp::Ordering::Greater => Ordering::Greater,
495 }
496 }
497}
498
499impl From<Ordering> for std::cmp::Ordering {
500 fn from(value: Ordering) -> Self {
501 match value {
502 Ordering::Less => std::cmp::Ordering::Less,
503 Ordering::Equal => std::cmp::Ordering::Equal,
504 Ordering::Greater => std::cmp::Ordering::Greater,
505 }
506 }
507}
508
509#[derive(Serialize, Deserialize, Debug, Clone)]
511pub enum PluginOutput {
512 Hello(ProtocolInfo),
514 Option(PluginOption),
516 CallResponse(PluginCallId, PluginCallResponse<PipelineDataHeader>),
519 EngineCall {
522 context: PluginCallId,
524 id: EngineCallId,
526 call: EngineCall<PipelineDataHeader>,
527 },
528 Data(StreamId, StreamData),
530 End(StreamId),
532 Drop(StreamId),
534 Ack(StreamId),
536}
537
538impl TryFrom<PluginOutput> for StreamMessage {
539 type Error = PluginOutput;
540
541 fn try_from(msg: PluginOutput) -> Result<StreamMessage, PluginOutput> {
542 match msg {
543 PluginOutput::Data(id, data) => Ok(StreamMessage::Data(id, data)),
544 PluginOutput::End(id) => Ok(StreamMessage::End(id)),
545 PluginOutput::Drop(id) => Ok(StreamMessage::Drop(id)),
546 PluginOutput::Ack(id) => Ok(StreamMessage::Ack(id)),
547 _ => Err(msg),
548 }
549 }
550}
551
552impl From<StreamMessage> for PluginOutput {
553 fn from(stream_msg: StreamMessage) -> PluginOutput {
554 match stream_msg {
555 StreamMessage::Data(id, data) => PluginOutput::Data(id, data),
556 StreamMessage::End(id) => PluginOutput::End(id),
557 StreamMessage::Drop(id) => PluginOutput::Drop(id),
558 StreamMessage::Ack(id) => PluginOutput::Ack(id),
559 }
560 }
561}
562
563#[derive(Serialize, Deserialize, Debug, Clone)]
567pub enum EngineCall<D> {
568 GetConfig,
570 GetPluginConfig,
572 GetEnvVar(String),
574 GetEnvVars,
576 GetCurrentDir,
578 AddEnvVar(String, Value),
580 GetHelp,
582 EnterForeground,
584 LeaveForeground,
586 GetSpanContents(Span),
588 EvalClosure {
590 closure: Spanned<Closure>,
594 positional: Vec<Value>,
596 input: D,
598 redirect_stdout: bool,
600 redirect_stderr: bool,
602 },
603 FindDecl(String),
605 GetBlockIR(BlockId),
607 CallDecl {
609 decl_id: DeclId,
611 call: EvaluatedCall,
613 input: D,
615 redirect_stdout: bool,
617 redirect_stderr: bool,
619 },
620}
621
622impl<D> EngineCall<D> {
623 pub fn name(&self) -> &'static str {
625 match self {
626 EngineCall::GetConfig => "GetConfig",
627 EngineCall::GetPluginConfig => "GetPluginConfig",
628 EngineCall::GetEnvVar(_) => "GetEnv",
629 EngineCall::GetEnvVars => "GetEnvs",
630 EngineCall::GetCurrentDir => "GetCurrentDir",
631 EngineCall::AddEnvVar(..) => "AddEnvVar",
632 EngineCall::GetHelp => "GetHelp",
633 EngineCall::EnterForeground => "EnterForeground",
634 EngineCall::LeaveForeground => "LeaveForeground",
635 EngineCall::GetSpanContents(_) => "GetSpanContents",
636 EngineCall::EvalClosure { .. } => "EvalClosure",
637 EngineCall::FindDecl(_) => "FindDecl",
638 EngineCall::GetBlockIR(_) => "GetBlockIR",
639 EngineCall::CallDecl { .. } => "CallDecl",
640 }
641 }
642
643 pub fn map_data<T>(
646 self,
647 f: impl FnOnce(D) -> Result<T, ShellError>,
648 ) -> Result<EngineCall<T>, ShellError> {
649 Ok(match self {
650 EngineCall::GetConfig => EngineCall::GetConfig,
651 EngineCall::GetPluginConfig => EngineCall::GetPluginConfig,
652 EngineCall::GetEnvVar(name) => EngineCall::GetEnvVar(name),
653 EngineCall::GetEnvVars => EngineCall::GetEnvVars,
654 EngineCall::GetCurrentDir => EngineCall::GetCurrentDir,
655 EngineCall::AddEnvVar(name, value) => EngineCall::AddEnvVar(name, value),
656 EngineCall::GetHelp => EngineCall::GetHelp,
657 EngineCall::EnterForeground => EngineCall::EnterForeground,
658 EngineCall::LeaveForeground => EngineCall::LeaveForeground,
659 EngineCall::GetSpanContents(span) => EngineCall::GetSpanContents(span),
660 EngineCall::EvalClosure {
661 closure,
662 positional,
663 input,
664 redirect_stdout,
665 redirect_stderr,
666 } => EngineCall::EvalClosure {
667 closure,
668 positional,
669 input: f(input)?,
670 redirect_stdout,
671 redirect_stderr,
672 },
673 EngineCall::FindDecl(name) => EngineCall::FindDecl(name),
674 EngineCall::GetBlockIR(block_id) => EngineCall::GetBlockIR(block_id),
675 EngineCall::CallDecl {
676 decl_id,
677 call,
678 input,
679 redirect_stdout,
680 redirect_stderr,
681 } => EngineCall::CallDecl {
682 decl_id,
683 call,
684 input: f(input)?,
685 redirect_stdout,
686 redirect_stderr,
687 },
688 })
689 }
690}
691
692#[derive(Serialize, Deserialize, Debug, Clone)]
695pub enum EngineCallResponse<D> {
696 Error(ShellError),
697 PipelineData(D),
698 Config(SharedCow<Config>),
699 ValueMap(HashMap<String, Value>),
700 Identifier(DeclId),
701 IrBlock(Box<IrBlock>),
702}
703
704impl<D> EngineCallResponse<D> {
705 pub fn map_data<T>(
708 self,
709 f: impl FnOnce(D) -> Result<T, ShellError>,
710 ) -> Result<EngineCallResponse<T>, ShellError> {
711 Ok(match self {
712 EngineCallResponse::Error(err) => EngineCallResponse::Error(err),
713 EngineCallResponse::PipelineData(data) => EngineCallResponse::PipelineData(f(data)?),
714 EngineCallResponse::Config(config) => EngineCallResponse::Config(config),
715 EngineCallResponse::ValueMap(map) => EngineCallResponse::ValueMap(map),
716 EngineCallResponse::Identifier(id) => EngineCallResponse::Identifier(id),
717 EngineCallResponse::IrBlock(ir) => EngineCallResponse::IrBlock(ir),
718 })
719 }
720}
721
722impl EngineCallResponse<PipelineData> {
723 pub fn value(value: Value) -> EngineCallResponse<PipelineData> {
725 EngineCallResponse::PipelineData(PipelineData::value(value, None))
726 }
727
728 pub const fn empty() -> EngineCallResponse<PipelineData> {
730 EngineCallResponse::PipelineData(PipelineData::empty())
731 }
732}