use crate::context::{SourceMap, SpanSource}; use crate::errors::ShellError; use crate::evaluate::Scope; use crate::object::Value; use crate::parser::hir; use crate::parser::{registry, Span, Spanned}; use crate::prelude::*; use getset::Getters; use serde::{Deserialize, Serialize}; use std::fmt; use std::ops::Deref; use std::path::PathBuf; use uuid::Uuid; #[derive(Deserialize, Serialize, Debug, Clone)] pub struct UnevaluatedCallInfo { pub args: hir::Call, pub source: Text, pub source_map: SourceMap, pub name_span: Option, } impl ToDebug for UnevaluatedCallInfo { fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result { self.args.fmt_debug(f, source) } } impl UnevaluatedCallInfo { fn name(&self) -> Result<&str, ShellError> { let head = &self.args.head(); match head.item() { hir::RawExpression::Literal(hir::Literal::Bare) => Ok(head.span.slice(&self.source)), hir::RawExpression::Literal(hir::Literal::String(span)) => Ok(span.slice(&self.source)), other => Err(ShellError::type_error( "Command name", head.type_name().spanned(head.span), )), } } fn evaluate( self, registry: ®istry::CommandRegistry, scope: &Scope, ) -> Result { let args = self.args.evaluate(registry, scope, &self.source)?; Ok(CallInfo { args, source_map: self.source_map, name_span: self.name_span, }) } } #[derive(Deserialize, Serialize, Debug)] pub struct CallInfo { pub args: registry::EvaluatedArgs, pub source_map: SourceMap, pub name_span: Option, } #[derive(Getters)] #[get = "crate"] pub struct CommandArgs { pub host: Arc>, pub env: Arc>, pub call_info: UnevaluatedCallInfo, pub input: InputStream, } impl ToDebug for CommandArgs { fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result { self.call_info.fmt_debug(f, source) } } impl CommandArgs { pub fn evaluate_once( self, registry: ®istry::CommandRegistry, ) -> Result { let host = self.host.clone(); let env = self.env.clone(); let input = self.input; let call_info = self.call_info.evaluate(registry, &Scope::empty())?; Ok(EvaluatedStaticCommandArgs::new(host, env, call_info, input)) } pub fn name_span(&self) -> Option { self.call_info.name_span } } pub enum EvaluatedInput { Static(InputStream), Filter(Spanned), } impl EvaluatedInput { pub fn stream(self) -> InputStream { match self { EvaluatedInput::Static(stream) => stream, EvaluatedInput::Filter(value) => vec![value].into(), } } } pub struct EvaluatedStaticCommandArgs { pub args: EvaluatedCommandArgs, pub input: InputStream, } impl Deref for EvaluatedStaticCommandArgs { type Target = EvaluatedCommandArgs; fn deref(&self) -> &Self::Target { &self.args } } impl EvaluatedStaticCommandArgs { pub fn new( host: Arc>, env: Arc>, call_info: CallInfo, input: impl Into, ) -> EvaluatedStaticCommandArgs { EvaluatedStaticCommandArgs { args: EvaluatedCommandArgs { host, env, call_info, }, input: input.into(), } } pub fn name_span(&self) -> Option { self.args.call_info.name_span } pub fn parts(self) -> (InputStream, registry::EvaluatedArgs) { let EvaluatedStaticCommandArgs { args, input } = self; (input, args.call_info.args) } } #[derive(Getters)] #[get = "pub"] pub struct EvaluatedFilterCommandArgs { args: EvaluatedCommandArgs, input: Spanned, } impl Deref for EvaluatedFilterCommandArgs { type Target = EvaluatedCommandArgs; fn deref(&self) -> &Self::Target { &self.args } } impl EvaluatedFilterCommandArgs { pub fn new( host: Arc>, env: Arc>, call_info: CallInfo, input: Spanned, ) -> EvaluatedFilterCommandArgs { EvaluatedFilterCommandArgs { args: EvaluatedCommandArgs { host, env, call_info, }, input, } } } #[derive(Getters)] #[get = "crate"] pub struct EvaluatedCommandArgs { pub host: Arc>, pub env: Arc>, pub call_info: CallInfo, } impl EvaluatedCommandArgs { pub fn parts(self) -> () {} pub fn call_args(&self) -> ®istry::EvaluatedArgs { &self.call_info.args } pub fn nth(&self, pos: usize) -> Option<&Spanned> { self.call_info.args.nth(pos) } pub fn positional_iter(&self) -> impl Iterator> { self.call_info.args.positional_iter() } pub fn expect_nth(&self, pos: usize) -> Result<&Spanned, ShellError> { self.call_info.args.expect_nth(pos) } pub fn len(&self) -> usize { self.call_info.args.len() } pub fn get(&self, name: &str) -> Option<&Spanned> { self.call_info.args.get(name) } #[allow(unused)] pub fn has(&self, name: &str) -> bool { self.call_info.args.has(name) } } pub struct SinkCommandArgs { pub ctx: Context, pub call_info: CallInfo, pub input: Vec>, } impl SinkCommandArgs { pub fn name_span(&self) -> Option { self.call_info.name_span } } #[derive(Debug, Serialize, Deserialize)] pub enum CommandAction { ChangePath(PathBuf), AddSpanSource(Uuid, SpanSource), Exit, } #[derive(Debug, Serialize, Deserialize)] pub enum ReturnSuccess { Value(Spanned), Action(CommandAction), } pub type ReturnValue = Result; impl From> for ReturnValue { fn from(input: Spanned) -> ReturnValue { Ok(ReturnSuccess::Value(input)) } } impl ReturnSuccess { pub fn change_cwd(path: PathBuf) -> ReturnValue { Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) } pub fn value(input: impl Into>) -> ReturnValue { Ok(ReturnSuccess::Value(input.into())) } pub fn action(input: CommandAction) -> ReturnValue { Ok(ReturnSuccess::Action(input)) } pub fn spanned_value(input: Value, span: Span) -> ReturnValue { Ok(ReturnSuccess::Value(Spanned::from_item(input, span))) } } pub trait Command: Send + Sync { fn run( &self, args: CommandArgs, registry: ®istry::CommandRegistry, ) -> Result; fn name(&self) -> &str; fn config(&self) -> registry::CommandConfig { registry::CommandConfig { name: self.name().to_string(), positional: vec![], rest_positional: true, named: indexmap::IndexMap::new(), is_filter: true, is_sink: false, } } } pub trait Sink { fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError>; fn name(&self) -> &str; fn config(&self) -> registry::CommandConfig { registry::CommandConfig { name: self.name().to_string(), positional: vec![], rest_positional: true, named: indexmap::IndexMap::new(), is_filter: false, is_sink: true, } } } pub struct FnFilterCommand { name: String, func: fn(EvaluatedFilterCommandArgs) -> Result, } impl Command for FnFilterCommand { fn name(&self) -> &str { &self.name } fn run( &self, args: CommandArgs, registry: ®istry::CommandRegistry, ) -> Result { let CommandArgs { host, env, call_info, input, } = args; let host: Arc> = host.clone(); let env: Arc> = env.clone(); let registry: registry::CommandRegistry = registry.clone(); let func = self.func; let result = input.values.map(move |it| { let registry = registry.clone(); let call_info = match call_info .clone() .evaluate(®istry, &Scope::it_value(it.clone())) { Err(err) => return OutputStream::from(vec![Err(err)]).values, Ok(args) => args, }; let args = EvaluatedFilterCommandArgs::new(host.clone(), env.clone(), call_info, it); match func(args) { Err(err) => return OutputStream::from(vec![Err(err)]).values, Ok(stream) => stream.values, } }); let result = result.flatten(); let result: BoxStream = result.boxed(); Ok(result.into()) } } pub struct FnRawCommand { name: String, func: Box< dyn Fn(CommandArgs, ®istry::CommandRegistry) -> Result + Send + Sync, >, } impl Command for FnRawCommand { fn run( &self, args: CommandArgs, registry: ®istry::CommandRegistry, ) -> Result { (self.func)(args, registry) } fn name(&self) -> &str { &self.name } } pub fn command( name: &str, func: Box< dyn Fn(CommandArgs, ®istry::CommandRegistry) -> Result + Send + Sync, >, ) -> Arc { Arc::new(FnRawCommand { name: name.to_string(), func, }) } pub fn filter( name: &str, func: fn(EvaluatedFilterCommandArgs) -> Result, ) -> Arc { Arc::new(FnFilterCommand { name: name.to_string(), func, }) } pub struct FnSink { name: String, func: Box Result<(), ShellError>>, } impl Sink for FnSink { fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError> { (self.func)(args) } fn name(&self) -> &str { &self.name } } pub fn sink( name: &str, func: Box Result<(), ShellError>>, ) -> Arc { Arc::new(FnSink { name: name.to_string(), func, }) }