mirror of
https://github.com/nushell/nushell.git
synced 2024-11-21 16:03:19 +01:00
Tests pass!
This commit is contained in:
parent
01223091ec
commit
5a8e041a48
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
history.txt
|
||||
tests/fixtures/nuplayground
|
41
src/cli.rs
41
src/cli.rs
@ -9,13 +9,11 @@ use crate::commands::plugin::JsonRpc;
|
||||
use crate::commands::plugin::{PluginCommand, PluginSink};
|
||||
use crate::context::Context;
|
||||
crate use crate::errors::ShellError;
|
||||
use crate::evaluate::Scope;
|
||||
use crate::git::current_branch;
|
||||
use crate::object::Value;
|
||||
use crate::parser::parse::span::Spanned;
|
||||
use crate::parser::registry;
|
||||
use crate::parser::registry::CommandConfig;
|
||||
use crate::parser::{Pipeline, PipelineElement, TokenNode};
|
||||
use crate::parser::{hir, Pipeline, PipelineElement, TokenNode};
|
||||
use crate::prelude::*;
|
||||
|
||||
use log::{debug, trace};
|
||||
@ -150,22 +148,22 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
use crate::commands::*;
|
||||
|
||||
context.add_commands(vec![
|
||||
command("first", Box::new(first::first)),
|
||||
command("pick", Box::new(pick::pick)),
|
||||
command("from-ini", Box::new(from_ini::from_ini)),
|
||||
command("from-csv", Box::new(from_csv::from_csv)),
|
||||
command("from-json", Box::new(from_json::from_json)),
|
||||
command("from-toml", Box::new(from_toml::from_toml)),
|
||||
command("from-xml", Box::new(from_xml::from_xml)),
|
||||
command("ps", Box::new(ps::ps)),
|
||||
command("ls", Box::new(ls::ls)),
|
||||
command("sysinfo", Box::new(sysinfo::sysinfo)),
|
||||
command("cd", Box::new(cd::cd)),
|
||||
command("first", Box::new(first::first)),
|
||||
command("size", Box::new(size::size)),
|
||||
command("from-csv", Box::new(from_csv::from_csv)),
|
||||
command("from-ini", Box::new(from_ini::from_ini)),
|
||||
command("from-json", Box::new(from_json::from_json)),
|
||||
command("from-toml", Box::new(from_toml::from_toml)),
|
||||
command("from-xml", Box::new(from_xml::from_xml)),
|
||||
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
||||
command("get", Box::new(get::get)),
|
||||
command("exit", Box::new(exit::exit)),
|
||||
command("lines", Box::new(lines::lines)),
|
||||
command("pick", Box::new(pick::pick)),
|
||||
command("split-column", Box::new(split_column::split_column)),
|
||||
command("split-row", Box::new(split_row::split_row)),
|
||||
command("lines", Box::new(lines::lines)),
|
||||
@ -348,10 +346,11 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
_ => pipeline.commands.push(ClassifiedCommand::Sink(SinkCommand {
|
||||
command: sink("autoview", Box::new(autoview::autoview)),
|
||||
name_span: None,
|
||||
args: registry::Args {
|
||||
positional: None,
|
||||
named: None,
|
||||
},
|
||||
args: hir::Call::new(
|
||||
Box::new(hir::Expression::synthetic_string("autoview")),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
})),
|
||||
}
|
||||
|
||||
@ -386,7 +385,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
|
||||
(Some(ClassifiedCommand::Sink(left)), None) => {
|
||||
let input_vec: Vec<Spanned<Value>> = input.objects.into_vec().await;
|
||||
if let Err(err) = left.run(ctx, input_vec) {
|
||||
if let Err(err) = left.run(ctx, input_vec, &Text::from(line)) {
|
||||
return LineResult::Error(line.clone(), err);
|
||||
}
|
||||
break;
|
||||
@ -395,20 +394,20 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
(
|
||||
Some(ClassifiedCommand::Internal(left)),
|
||||
Some(ClassifiedCommand::External(_)),
|
||||
) => match left.run(ctx, input).await {
|
||||
) => match left.run(ctx, input, Text::from(line)).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
},
|
||||
|
||||
(Some(ClassifiedCommand::Internal(left)), Some(_)) => {
|
||||
match left.run(ctx, input).await {
|
||||
match left.run(ctx, input, Text::from(line)).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
}
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Internal(left)), None) => {
|
||||
match left.run(ctx, input).await {
|
||||
match left.run(ctx, input, Text::from(line)).await {
|
||||
Ok(val) => ClassifiedInputStream::from_input_stream(val),
|
||||
Err(err) => return LineResult::Error(line.clone(), err),
|
||||
}
|
||||
@ -487,11 +486,10 @@ fn classify_command(
|
||||
true => {
|
||||
let command = context.get_command(name);
|
||||
let config = command.config();
|
||||
let scope = Scope::empty();
|
||||
|
||||
trace!(target: "nu::build_pipeline", "classifying {:?}", config);
|
||||
|
||||
let args = config.evaluate_args(call, context, &scope, source)?;
|
||||
let args: hir::Call = config.parse_args(call, context.registry(), source)?;
|
||||
|
||||
Ok(ClassifiedCommand::Internal(InternalCommand {
|
||||
command,
|
||||
@ -504,9 +502,8 @@ fn classify_command(
|
||||
true => {
|
||||
let command = context.get_sink(name);
|
||||
let config = command.config();
|
||||
let scope = Scope::empty();
|
||||
|
||||
let args = config.evaluate_args(call, context, &scope, source)?;
|
||||
let args = config.parse_args(call, context.registry(), source)?;
|
||||
|
||||
Ok(ClassifiedCommand::Sink(SinkCommand {
|
||||
command,
|
||||
|
@ -4,7 +4,6 @@ crate mod macros;
|
||||
crate mod args;
|
||||
crate mod autoview;
|
||||
crate mod cd;
|
||||
crate mod rm;
|
||||
crate mod classified;
|
||||
crate mod clip;
|
||||
crate mod command;
|
||||
@ -25,6 +24,7 @@ crate mod pick;
|
||||
crate mod plugin;
|
||||
crate mod ps;
|
||||
crate mod reject;
|
||||
crate mod rm;
|
||||
crate mod save;
|
||||
crate mod size;
|
||||
crate mod skip_while;
|
||||
@ -42,9 +42,9 @@ crate mod trim;
|
||||
crate mod vtable;
|
||||
crate mod where_;
|
||||
|
||||
crate use command::command;
|
||||
crate use command::{command, filter, EvaluatedFilterCommandArgs, EvaluatedStaticCommandArgs};
|
||||
crate use config::Config;
|
||||
crate use rm::Remove;
|
||||
crate use open::Open;
|
||||
crate use rm::Remove;
|
||||
crate use skip_while::SkipWhile;
|
||||
crate use where_::Where;
|
||||
|
@ -2,8 +2,10 @@ use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use std::env;
|
||||
|
||||
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.lock().unwrap();
|
||||
pub fn cd(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.clone();
|
||||
let env = env.lock().unwrap();
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let cwd = env.path().to_path_buf();
|
||||
|
||||
let path = match args.nth(0) {
|
||||
@ -13,7 +15,7 @@ pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Can not change to home directory",
|
||||
"can not go to home",
|
||||
args.call_info.name_span,
|
||||
args.name_span(),
|
||||
))
|
||||
}
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::commands::command::Sink;
|
||||
use crate::context::SourceMap;
|
||||
use crate::parser::{registry::Args, Span, Spanned, TokenNode};
|
||||
use crate::evaluate::Scope;
|
||||
use crate::parser::{hir, Span, Spanned, TokenNode};
|
||||
use crate::prelude::*;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use futures::stream::StreamExt;
|
||||
@ -101,7 +102,7 @@ impl ClassifiedCommand {
|
||||
crate struct SinkCommand {
|
||||
crate command: Arc<dyn Sink>,
|
||||
crate name_span: Option<Span>,
|
||||
crate args: Args,
|
||||
crate args: hir::Call,
|
||||
}
|
||||
|
||||
impl SinkCommand {
|
||||
@ -109,8 +110,12 @@ impl SinkCommand {
|
||||
self,
|
||||
context: &mut Context,
|
||||
input: Vec<Spanned<Value>>,
|
||||
source: &Text,
|
||||
) -> Result<(), ShellError> {
|
||||
context.run_sink(self.command, self.name_span.clone(), self.args, input)
|
||||
let args = self
|
||||
.args
|
||||
.evaluate(context.registry(), &Scope::empty(), source)?;
|
||||
context.run_sink(self.command, self.name_span.clone(), args, input)
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +123,7 @@ crate struct InternalCommand {
|
||||
crate command: Arc<dyn Command>,
|
||||
crate name_span: Option<Span>,
|
||||
crate source_map: SourceMap,
|
||||
crate args: Args,
|
||||
crate args: hir::Call,
|
||||
}
|
||||
|
||||
impl InternalCommand {
|
||||
@ -126,11 +131,12 @@ impl InternalCommand {
|
||||
self,
|
||||
context: &mut Context,
|
||||
input: ClassifiedInputStream,
|
||||
source: Text,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
if log_enabled!(log::Level::Trace) {
|
||||
trace!(target: "nu::run::internal", "->");
|
||||
trace!(target: "nu::run::internal", "{}", self.command.name());
|
||||
trace!(target: "nu::run::internal", "{:?}", self.args.debug());
|
||||
trace!(target: "nu::run::internal", "{}", self.args.debug(&source));
|
||||
}
|
||||
|
||||
let objects: InputStream =
|
||||
@ -141,6 +147,7 @@ impl InternalCommand {
|
||||
self.name_span.clone(),
|
||||
self.source_map,
|
||||
self.args,
|
||||
source,
|
||||
objects,
|
||||
)?;
|
||||
|
||||
|
@ -16,7 +16,7 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
}
|
||||
|
||||
let string = i.as_string().map_err(labelled(
|
||||
args.call_info.name_span,
|
||||
args.name_span(),
|
||||
"Given non-string data",
|
||||
"expected strings from pipeline",
|
||||
))?;
|
||||
|
@ -1,20 +1,62 @@
|
||||
use crate::context::SourceMap;
|
||||
use crate::context::SpanSource;
|
||||
use crate::context::{SourceMap, SpanSource};
|
||||
use crate::errors::ShellError;
|
||||
use crate::evaluate::Scope;
|
||||
use crate::object::Value;
|
||||
use crate::parser::{
|
||||
registry::{self, Args},
|
||||
Span, Spanned,
|
||||
};
|
||||
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<Span>,
|
||||
}
|
||||
|
||||
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<CallInfo, ShellError> {
|
||||
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: Args,
|
||||
pub args: registry::EvaluatedArgs,
|
||||
pub source_map: SourceMap,
|
||||
pub name_span: Option<Span>,
|
||||
}
|
||||
@ -22,13 +64,137 @@ pub struct CallInfo {
|
||||
#[derive(Getters)]
|
||||
#[get = "crate"]
|
||||
pub struct CommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host + Send>>,
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub env: Arc<Mutex<Environment>>,
|
||||
pub call_info: CallInfo,
|
||||
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<EvaluatedStaticCommandArgs, ShellError> {
|
||||
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<Span> {
|
||||
self.call_info.name_span
|
||||
}
|
||||
}
|
||||
|
||||
pub enum EvaluatedInput {
|
||||
Static(InputStream),
|
||||
Filter(Spanned<Value>),
|
||||
}
|
||||
|
||||
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<Mutex<dyn Host>>,
|
||||
env: Arc<Mutex<Environment>>,
|
||||
call_info: CallInfo,
|
||||
input: impl Into<InputStream>,
|
||||
) -> EvaluatedStaticCommandArgs {
|
||||
EvaluatedStaticCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
env,
|
||||
call_info,
|
||||
},
|
||||
input: input.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name_span(&self) -> Option<Span> {
|
||||
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<Value>,
|
||||
}
|
||||
|
||||
impl Deref for EvaluatedFilterCommandArgs {
|
||||
type Target = EvaluatedCommandArgs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.args
|
||||
}
|
||||
}
|
||||
|
||||
impl EvaluatedFilterCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<Mutex<dyn Host>>,
|
||||
env: Arc<Mutex<Environment>>,
|
||||
call_info: CallInfo,
|
||||
input: Spanned<Value>,
|
||||
) -> EvaluatedFilterCommandArgs {
|
||||
EvaluatedFilterCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
env,
|
||||
call_info,
|
||||
},
|
||||
input,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[get = "crate"]
|
||||
pub struct EvaluatedCommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
pub env: Arc<Mutex<Environment>>,
|
||||
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<Value>> {
|
||||
self.call_info.args.nth(pos)
|
||||
}
|
||||
@ -61,6 +227,12 @@ pub struct SinkCommandArgs {
|
||||
pub input: Vec<Spanned<Value>>,
|
||||
}
|
||||
|
||||
impl SinkCommandArgs {
|
||||
pub fn name_span(&self) -> Option<Span> {
|
||||
self.call_info.name_span
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum CommandAction {
|
||||
ChangePath(PathBuf),
|
||||
@ -100,8 +272,12 @@ impl ReturnSuccess {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Command {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError>;
|
||||
pub trait Command: Send + Sync {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError>;
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn config(&self) -> registry::CommandConfig {
|
||||
@ -132,14 +308,74 @@ pub trait Sink {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnCommand {
|
||||
pub struct FnFilterCommand {
|
||||
name: String,
|
||||
func: Box<dyn Fn(CommandArgs) -> Result<OutputStream, ShellError>>,
|
||||
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
}
|
||||
|
||||
impl Command for FnCommand {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
(self.func)(args)
|
||||
impl Command for FnFilterCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let CommandArgs {
|
||||
host,
|
||||
env,
|
||||
call_info,
|
||||
input,
|
||||
} = args;
|
||||
|
||||
let host: Arc<Mutex<dyn Host>> = host.clone();
|
||||
let env: Arc<Mutex<Environment>> = 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<ReturnValue> = result.boxed();
|
||||
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FnRawCommand {
|
||||
name: String,
|
||||
func: Box<
|
||||
dyn Fn(CommandArgs, ®istry::CommandRegistry) -> Result<OutputStream, ShellError>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>,
|
||||
}
|
||||
|
||||
impl Command for FnRawCommand {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
(self.func)(args, registry)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
@ -149,9 +385,23 @@ impl Command for FnCommand {
|
||||
|
||||
pub fn command(
|
||||
name: &str,
|
||||
func: Box<dyn Fn(CommandArgs) -> Result<OutputStream, ShellError>>,
|
||||
func: Box<
|
||||
dyn Fn(CommandArgs, ®istry::CommandRegistry) -> Result<OutputStream, ShellError>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>,
|
||||
) -> Arc<dyn Command> {
|
||||
Arc::new(FnCommand {
|
||||
Arc::new(FnRawCommand {
|
||||
name: name.to_string(),
|
||||
func,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn filter(
|
||||
name: &str,
|
||||
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
) -> Arc<dyn Command> {
|
||||
Arc::new(FnFilterCommand {
|
||||
name: name.to_string(),
|
||||
func,
|
||||
})
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::commands::EvaluatedStaticCommandArgs;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::config;
|
||||
use crate::object::Value;
|
||||
use crate::object::{config, Value};
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{CommandConfig, NamedType};
|
||||
use crate::parser::registry::{self, CommandConfig, NamedType};
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use std::iter::FromIterator;
|
||||
@ -12,9 +12,15 @@ use std::iter::FromIterator;
|
||||
pub struct Config;
|
||||
|
||||
impl Command for Config {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
config(args)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"config"
|
||||
}
|
||||
@ -38,11 +44,11 @@ impl Command for Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut result = crate::object::config::config(args.call_info.name_span)?;
|
||||
pub fn config(args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut result = crate::object::config::config(args.name_span())?;
|
||||
|
||||
trace!("{:#?}", args.call_info.args.positional);
|
||||
trace!("{:#?}", args.call_info.args.named);
|
||||
trace!("{:#?}", args.call_args().positional);
|
||||
trace!("{:#?}", args.call_args().named);
|
||||
|
||||
if let Some(v) = args.get("get") {
|
||||
let key = v.as_string()?;
|
||||
@ -95,7 +101,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
}
|
||||
|
||||
if args.len() == 0 {
|
||||
return Ok(vec![Value::Object(result.into()).spanned(args.call_info.name_span)].into());
|
||||
return Ok(vec![Value::Object(result.into()).spanned(args.name_span())].into());
|
||||
}
|
||||
|
||||
Err(ShellError::string(format!("Unimplemented")))
|
||||
|
@ -2,6 +2,6 @@ use crate::commands::command::CommandAction;
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn exit(_args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn exit(_args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::Exit))].into())
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
|
||||
// TODO: "Amount remaining" wrapper
|
||||
|
||||
pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn first(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"First requires an amount",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
args.name_span(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -25,7 +28,7 @@ pub fn first(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
}
|
||||
};
|
||||
|
||||
let input = args.input;
|
||||
|
||||
Ok(OutputStream::from_input(input.values.take(amount as u64)))
|
||||
Ok(OutputStream::from_input(
|
||||
args.input.values.take(amount as u64),
|
||||
))
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ pub fn from_csv_string_to_value(
|
||||
s: String,
|
||||
span: impl Into<Span>,
|
||||
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
|
||||
|
||||
let mut reader = ReaderBuilder::new()
|
||||
.has_headers(false)
|
||||
.from_reader(s.as_bytes());
|
||||
@ -49,9 +48,10 @@ pub fn from_csv_string_to_value(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
|
@ -37,9 +37,11 @@ pub fn from_ini_string_to_value(
|
||||
Ok(convert_ini_top_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_ini(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
|
@ -43,9 +43,14 @@ pub fn from_json_string_to_value(
|
||||
Ok(convert_json_value_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_json(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
|
@ -41,9 +41,14 @@ pub fn from_toml_string_to_value(
|
||||
Ok(convert_toml_value_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_toml(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
|
@ -59,9 +59,10 @@ pub fn from_xml_string_to_value(
|
||||
Ok(from_document_to_value(&parsed, span))
|
||||
}
|
||||
|
||||
pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_xml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
|
@ -48,9 +48,13 @@ pub fn from_yaml_string_to_value(
|
||||
Ok(convert_yaml_value_to_nu_value(&v, span))
|
||||
}
|
||||
|
||||
pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn from_yaml(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let span = args.name_span();
|
||||
let out = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(move |a| match a.item {
|
||||
|
@ -21,36 +21,37 @@ fn get_member(path: &str, span: Span, obj: &Spanned<Value>) -> Result<Spanned<Va
|
||||
Ok(current.clone())
|
||||
}
|
||||
|
||||
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
pub fn get(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let len = args.len();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Get requires a field or field path",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let amount = args.expect_nth(0)?.as_i64();
|
||||
let (input, args) = args.parts();
|
||||
let positional = args.positional;
|
||||
|
||||
// If it's a number, get the row instead of the column
|
||||
if let Ok(amount) = amount {
|
||||
return Ok(args
|
||||
.input
|
||||
.values
|
||||
.skip(amount as u64)
|
||||
.take(1)
|
||||
.from_input_stream());
|
||||
return Ok(input.values.skip(amount as u64).take(1).from_input_stream());
|
||||
}
|
||||
|
||||
let fields: Result<Vec<(String, Span)>, _> = args
|
||||
.positional_iter()
|
||||
let fields: Result<Vec<(String, Span)>, _> = positional
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| (a.as_string().map(|x| (x, a.span))))
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
|
||||
let stream = args
|
||||
.input
|
||||
let stream = input
|
||||
.values
|
||||
.map(move |item| {
|
||||
let mut result = VecDeque::new();
|
||||
|
@ -5,9 +5,12 @@ use log::trace;
|
||||
|
||||
// TODO: "Amount remaining" wrapper
|
||||
|
||||
pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn lines(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let input = args.input;
|
||||
let span = args.call_info.name_span;
|
||||
|
||||
let input: InputStream = trace_stream!(target: "nu::trace_stream::lines", "input" = input);
|
||||
|
||||
let stream = input
|
||||
.values
|
||||
|
@ -4,8 +4,10 @@ use crate::parser::Spanned;
|
||||
use crate::prelude::*;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.lock().unwrap();
|
||||
pub fn ls(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.clone();
|
||||
let env = env.lock().unwrap();
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let path = env.path.to_path_buf();
|
||||
let mut full_path = PathBuf::from(path);
|
||||
match &args.nth(0) {
|
||||
@ -30,7 +32,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
args.call_info.name_span,
|
||||
args.name_span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -40,7 +42,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut shell_entries = VecDeque::new();
|
||||
|
||||
for entry in entries {
|
||||
let value = dir_entry_dict(&entry?, args.call_info.name_span)?;
|
||||
let value = dir_entry_dict(&entry?, args.name_span())?;
|
||||
shell_entries.push_back(ReturnSuccess::value(value))
|
||||
}
|
||||
Ok(shell_entries.to_output_stream())
|
||||
|
@ -36,13 +36,14 @@ macro_rules! command {
|
||||
pub struct $export;
|
||||
|
||||
impl Command for $export {
|
||||
fn run(&self, $args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn command($args: CommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> {
|
||||
fn run(&self, $args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
fn command($args: EvaluatedCommandArgs, ( $($param_name),*, ): ( $($param_type),*, )) -> Result<OutputStream, ShellError> {
|
||||
let output = $body;
|
||||
|
||||
Ok(output.boxed().to_output_stream())
|
||||
}
|
||||
|
||||
let $args = $args.evaluate_once(registry)?;
|
||||
let tuple = ( $($extract ,)* );
|
||||
command( $args, tuple )
|
||||
}
|
||||
|
@ -1,69 +1,152 @@
|
||||
use crate::context::SpanSource;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{Primitive, Switch, Value};
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::parse::span::Span;
|
||||
use crate::parser::registry::{self, CommandConfig, NamedType, PositionalType};
|
||||
use crate::prelude::*;
|
||||
use indexmap::IndexMap;
|
||||
use mime::Mime;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
|
||||
command! {
|
||||
Open as open(args, path: Spanned<PathBuf>, --raw: Switch,) {
|
||||
let span = args.call_info.name_span;
|
||||
pub struct Open;
|
||||
|
||||
let cwd = args
|
||||
.env
|
||||
.lock()
|
||||
.unwrap()
|
||||
.path()
|
||||
.to_path_buf();
|
||||
impl Command for Open {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.clone();
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let path = <Spanned<PathBuf>>::extract(args.expect_nth(0)?)?;
|
||||
let raw = args.has("raw");
|
||||
|
||||
let span = args.name_span();
|
||||
|
||||
let cwd = env.lock().unwrap().path().to_path_buf();
|
||||
let full_path = PathBuf::from(cwd);
|
||||
|
||||
let path_str = path.to_str().ok_or(ShellError::type_error("Path", "invalid path".spanned(path.span)))?;
|
||||
let path_str = path.to_str().ok_or(ShellError::type_error(
|
||||
"Path",
|
||||
"invalid path".spanned(path.span),
|
||||
))?;
|
||||
|
||||
let (file_extension, contents, contents_span, span_source) = fetch(&full_path, path_str, path.span)?;
|
||||
let (file_extension, contents, contents_span, span_source) =
|
||||
fetch(&full_path, path_str, path.span)?;
|
||||
|
||||
let file_extension = if raw.is_present() {
|
||||
None
|
||||
} else {
|
||||
file_extension
|
||||
};
|
||||
let file_extension = if raw { None } else { file_extension };
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
|
||||
if let Some(uuid) = contents_span.source {
|
||||
// If we have loaded something, track its source
|
||||
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(uuid, span_source)))
|
||||
stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(
|
||||
uuid,
|
||||
span_source,
|
||||
)))
|
||||
}
|
||||
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(string)) => {
|
||||
let value = parse_as_value(
|
||||
file_extension,
|
||||
string,
|
||||
contents_span,
|
||||
span,
|
||||
)?;
|
||||
let value = parse_as_value(file_extension, string, contents_span, span)?;
|
||||
|
||||
match value {
|
||||
Spanned { item: Value::List(list), .. } => {
|
||||
Spanned {
|
||||
item: Value::List(list),
|
||||
..
|
||||
} => {
|
||||
for elem in list {
|
||||
stream.push_back(ReturnSuccess::value(elem));
|
||||
}
|
||||
}
|
||||
x => stream.push_back(ReturnSuccess::value(x))
|
||||
x => stream.push_back(ReturnSuccess::value(x)),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))),
|
||||
};
|
||||
|
||||
stream
|
||||
Ok(stream.boxed().to_output_stream())
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"open"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
let mut named = IndexMap::default();
|
||||
named.insert("raw".to_string(), NamedType::Switch);
|
||||
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![PositionalType::mandatory("path", SyntaxType::Block)],
|
||||
rest_positional: false,
|
||||
named,
|
||||
is_sink: true,
|
||||
is_filter: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// command! {
|
||||
// Open as open(args, path: Spanned<PathBuf>, --raw: Switch,) {
|
||||
// let span = args.name_span();
|
||||
// let env = args.env.clone();
|
||||
|
||||
// let path = env
|
||||
// .lock()
|
||||
// .unwrap()
|
||||
// .path()
|
||||
// .to_path_buf();
|
||||
|
||||
// let full_path = PathBuf::from(cwd);
|
||||
|
||||
// let path_str = path.to_str().ok_or(ShellError::type_error("Path", "invalid path".spanned(path.span)))?;
|
||||
|
||||
// let (file_extension, contents, contents_span, span_source) = fetch(&full_path, path_str, path.span)?;
|
||||
|
||||
// let file_extension = if raw.is_present() {
|
||||
// None
|
||||
// } else {
|
||||
// file_extension
|
||||
// };
|
||||
|
||||
// let mut stream = VecDeque::new();
|
||||
|
||||
// if let Some(uuid) = contents_span.source {
|
||||
// // If we have loaded something, track its source
|
||||
// stream.push_back(ReturnSuccess::action(CommandAction::AddSpanSource(uuid, span_source)))
|
||||
// }
|
||||
|
||||
// match contents {
|
||||
// Value::Primitive(Primitive::String(string)) => {
|
||||
// let value = parse_as_value(
|
||||
// file_extension,
|
||||
// string,
|
||||
// contents_span,
|
||||
// span,
|
||||
// )?;
|
||||
|
||||
// match value {
|
||||
// Spanned { item: Value::List(list), .. } => {
|
||||
// for elem in list {
|
||||
// stream.push_back(ReturnSuccess::value(elem));
|
||||
// }
|
||||
// }
|
||||
// x => stream.push_back(ReturnSuccess::value(x))
|
||||
// }
|
||||
// },
|
||||
|
||||
// other => stream.push_back(ReturnSuccess::value(other.spanned(contents_span))),
|
||||
// };
|
||||
|
||||
// stream
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn fetch(
|
||||
cwd: &PathBuf,
|
||||
location: &str,
|
||||
|
@ -1,19 +1,30 @@
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::base::select_fields;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
pub fn pick(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let len = args.len();
|
||||
let span = args.name_span();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Pick requires fields",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields: Result<Vec<String>, _> = args
|
||||
.positional
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| a.as_string())
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
let input = args.input;
|
||||
|
||||
let objects = input
|
||||
.values
|
||||
|
@ -41,8 +41,12 @@ pub struct PluginCommand {
|
||||
}
|
||||
|
||||
impl Command for PluginCommand {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
filter_plugin(self.path.clone(), args)
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
filter_plugin(self.path.clone(), args, registry)
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
@ -71,7 +75,13 @@ impl Sink for PluginSink {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn filter_plugin(
|
||||
path: String,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
|
||||
let mut child = std::process::Command::new(path)
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
@ -84,7 +94,7 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
|
||||
|
||||
let mut reader = BufReader::new(stdout);
|
||||
|
||||
let request = JsonRpc::new("begin_filter", args.call_info);
|
||||
let request = JsonRpc::new("begin_filter", args.args.call_info);
|
||||
let request_raw = serde_json::to_string(&request).unwrap();
|
||||
stdin.write(format!("{}\n", request_raw).as_bytes())?;
|
||||
let mut input = String::new();
|
||||
|
@ -3,14 +3,14 @@ use crate::object::process::process_dict;
|
||||
use crate::prelude::*;
|
||||
use sysinfo::{RefreshKind, SystemExt};
|
||||
|
||||
pub fn ps(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn ps(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let mut system = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes());
|
||||
system.refresh_processes();
|
||||
let list = system.get_process_list();
|
||||
|
||||
let list = list
|
||||
.into_iter()
|
||||
.map(|(_, process)| process_dict(process, args.call_info.name_span))
|
||||
.map(|(_, process)| process_dict(process, args.name_span()))
|
||||
.collect::<VecDeque<_>>();
|
||||
|
||||
Ok(list.from_input_stream())
|
||||
|
@ -2,21 +2,31 @@ use crate::errors::ShellError;
|
||||
use crate::object::base::reject_fields;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_span;
|
||||
pub fn reject(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.name_span();
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let len = args.len();
|
||||
let span = args.name_span();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
if args.len() == 0 {
|
||||
if len == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Reject requires fields",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
let fields: Result<Vec<String>, _> = args
|
||||
.positional
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| a.as_string())
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
|
||||
let stream = args.input.values.map(move |item| {
|
||||
let stream = input.values.map(move |item| {
|
||||
reject_fields(&item, &fields, item.span)
|
||||
.into_spanned_value()
|
||||
.spanned(name_span)
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::commands::EvaluatedStaticCommandArgs;
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{CommandConfig, NamedType, PositionalType};
|
||||
@ -7,8 +8,13 @@ use indexmap::IndexMap;
|
||||
pub struct Remove;
|
||||
|
||||
impl Command for Remove {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
rm(args)
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let env = args.env.clone();
|
||||
rm(args.evaluate_once(registry)?, env)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
@ -30,8 +36,11 @@ impl Command for Remove {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rm(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = args.env.lock().unwrap().path().to_path_buf();
|
||||
pub fn rm(
|
||||
args: EvaluatedStaticCommandArgs,
|
||||
env: Arc<Mutex<Environment>>,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = env.lock().unwrap().path().to_path_buf();
|
||||
|
||||
match args
|
||||
.nth(0)
|
||||
@ -48,7 +57,7 @@ pub fn rm(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
return Err(ShellError::labeled_error(
|
||||
"is a directory",
|
||||
"",
|
||||
args.call_info.name_span.unwrap(),
|
||||
args.name_span().unwrap(),
|
||||
));
|
||||
}
|
||||
std::fs::remove_dir_all(&full_path).expect("can not remove directory");
|
||||
|
@ -13,7 +13,7 @@ pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Save requires a filepath",
|
||||
"needs path",
|
||||
args.call_info.name_span,
|
||||
args.name_span(),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
||||
use crate::object::{SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn size(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
Ok(input
|
||||
.values
|
||||
|
@ -6,8 +6,12 @@ use crate::prelude::*;
|
||||
pub struct SkipWhile;
|
||||
|
||||
impl Command for SkipWhile {
|
||||
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
skip_while(args)
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
skip_while(args, registry)
|
||||
}
|
||||
fn name(&self) -> &str {
|
||||
"skip-while"
|
||||
@ -25,18 +29,24 @@ impl Command for SkipWhile {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_while(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if args.len() == 0 {
|
||||
pub fn skip_while(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let block = args.expect_nth(0)?.as_block()?;
|
||||
let span = args.name_span();
|
||||
let len = args.len();
|
||||
let input = args.input;
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Where requires a condition",
|
||||
"needs condition",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let block = args.nth(0).unwrap().as_block()?;
|
||||
let input = args.input;
|
||||
|
||||
let objects = input.values.skip_while(move |item| {
|
||||
let result = block.invoke(&item);
|
||||
|
||||
|
@ -1,11 +1,20 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let fields: Result<Vec<_>, _> = args.positional_iter().map(|a| a.as_string()).collect();
|
||||
pub fn sort_by(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let (input, args) = args.parts();
|
||||
|
||||
let fields: Result<Vec<_>, _> = args
|
||||
.positional
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|a| a.as_string())
|
||||
.collect();
|
||||
|
||||
let fields = fields?;
|
||||
|
||||
let output = args.input.values.collect::<Vec<_>>();
|
||||
let output = input.values.collect::<Vec<_>>();
|
||||
|
||||
let output = output.map(move |mut vec| {
|
||||
vec.sort_by_key(|item| {
|
||||
|
@ -3,20 +3,24 @@ use crate::object::{Primitive, SpannedDictBuilder, Value};
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
|
||||
pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let positional: Vec<_> = args.positional_iter().cloned().collect();
|
||||
let span = args.call_info.name_span;
|
||||
pub fn split_column(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
let positional: Vec<_> = args.positional.iter().flatten().cloned().collect();
|
||||
|
||||
if positional.len() == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Split-column needs more information",
|
||||
"needs parameter (eg split-column \",\")",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
|
@ -4,20 +4,25 @@ use crate::parser::Spanned;
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
|
||||
pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let positional: Vec<Spanned<Value>> = args.positional_iter().cloned().collect();
|
||||
let span = args.call_info.name_span;
|
||||
pub fn split_row(
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let span = args.name_span();
|
||||
let len = args.len();
|
||||
let (input, args) = args.parts();
|
||||
|
||||
if positional.len() == 0 {
|
||||
let positional: Vec<Spanned<Value>> = args.positional.iter().flatten().cloned().collect();
|
||||
|
||||
if len == 0 {
|
||||
return Err(ShellError::maybe_labeled_error(
|
||||
"Split-row needs more information",
|
||||
"needs parameter (eg split-row \"\\n\")",
|
||||
args.call_info.name_span,
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
let input = args.input;
|
||||
|
||||
let stream = input
|
||||
.values
|
||||
.map(move |v| match v.item {
|
||||
|
@ -6,8 +6,8 @@ use crate::prelude::*;
|
||||
use sys_info::*;
|
||||
use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt};
|
||||
|
||||
pub fn sysinfo(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.call_info.name_span;
|
||||
pub fn sysinfo(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let name_span = args.name_span();
|
||||
let mut idx = SpannedDictBuilder::new(name_span);
|
||||
|
||||
if let (Ok(name), Ok(version)) = (os_type(), os_release()) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_array(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input.values.collect();
|
||||
|
||||
Ok(out
|
||||
|
@ -1,10 +1,9 @@
|
||||
use crate::object::{Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
use log::debug;
|
||||
use csv::WriterBuilder;
|
||||
use log::debug;
|
||||
|
||||
pub fn value_to_csv_value(v: &Value) -> Value {
|
||||
|
||||
debug!("value_to_csv_value(Value::Object(v)) where v = {:?}", v);
|
||||
|
||||
match v {
|
||||
@ -13,7 +12,7 @@ pub fn value_to_csv_value(v: &Value) -> Value {
|
||||
Value::Object(o) => Value::Object(o.clone()),
|
||||
Value::List(l) => Value::List(l.clone()),
|
||||
Value::Block(_) => Value::Primitive(Primitive::Nothing),
|
||||
_ => Value::Primitive(Primitive::Nothing)
|
||||
_ => Value::Primitive(Primitive::Nothing),
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,7 +20,6 @@ pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
|
||||
match v {
|
||||
Value::List(_l) => return Ok(String::from("[list list]")),
|
||||
Value::Object(o) => {
|
||||
|
||||
debug!("to_csv:to_string(Value::Object(v)) where v = {:?}", v);
|
||||
|
||||
let mut wtr = WriterBuilder::new().from_writer(vec![]);
|
||||
@ -32,34 +30,33 @@ pub fn to_string(v: &Value) -> Result<String, Box<dyn std::error::Error>> {
|
||||
fields.push_back(k.clone());
|
||||
values.push_back(to_string(&v)?);
|
||||
}
|
||||
|
||||
|
||||
wtr.write_record(fields).expect("can not write.");
|
||||
wtr.write_record(values).expect("can not write.");
|
||||
|
||||
return Ok(String::from_utf8(wtr.into_inner()?)?)
|
||||
},
|
||||
return Ok(String::from_utf8(wtr.into_inner()?)?);
|
||||
}
|
||||
Value::Primitive(Primitive::String(s)) => return Ok(s.to_string()),
|
||||
_ => return Err("Bad input".into())
|
||||
_ => return Err("Bad input".into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_csv(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_csv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(
|
||||
move |a| match to_string(&value_to_csv_value(&a.item)) {
|
||||
|
||||
Ok(x) => {
|
||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
||||
}
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Can not convert to CSV string",
|
||||
"can not convert piped data to CSV string",
|
||||
name_span,
|
||||
)),
|
||||
},
|
||||
)
|
||||
.map(move |a| match to_string(&value_to_csv_value(&a.item)) {
|
||||
Ok(x) => {
|
||||
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span))
|
||||
}
|
||||
Err(_) => Err(ShellError::maybe_labeled_error(
|
||||
"Can not convert to CSV string",
|
||||
"can not convert piped data to CSV string",
|
||||
name_span,
|
||||
)),
|
||||
})
|
||||
.to_output_stream())
|
||||
}
|
||||
|
@ -40,9 +40,11 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_json(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
.map(
|
||||
|
@ -30,9 +30,10 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_toml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
|
||||
Ok(out
|
||||
.values
|
||||
|
@ -38,9 +38,10 @@ pub fn value_to_yaml_value(v: &Value) -> serde_yaml::Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn to_yaml(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let name_span = args.name_span();
|
||||
let out = args.input;
|
||||
let name_span = args.call_info.name_span;
|
||||
Ok(out
|
||||
.values
|
||||
.map(
|
||||
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn trim(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let input = args.input;
|
||||
|
||||
Ok(input
|
||||
|
@ -1,23 +1,76 @@
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Block;
|
||||
use crate::object::base as value;
|
||||
use crate::object::{types, Value};
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry::{self, CommandConfig, PositionalType};
|
||||
use crate::prelude::*;
|
||||
|
||||
use futures::future::ready;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
|
||||
command! {
|
||||
Where as where(args, condition: Block,) {
|
||||
let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = args.input);
|
||||
pub struct Where;
|
||||
|
||||
input.values.filter_map(move |item| {
|
||||
let result = condition.invoke(&item);
|
||||
impl Command for Where {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
let condition = value::Block::extract(args.expect_nth(0)?)?;
|
||||
let input = args.input;
|
||||
let input: InputStream =
|
||||
trace_stream!(target: "nu::trace_stream::where", "where input" = input);
|
||||
|
||||
let return_value = match result {
|
||||
Err(err) => Some(Err(err)),
|
||||
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
|
||||
_ => None,
|
||||
};
|
||||
Ok(input
|
||||
.values
|
||||
.filter_map(move |item| {
|
||||
let result = condition.invoke(&item);
|
||||
|
||||
ready(return_value)
|
||||
})
|
||||
let return_value = match result {
|
||||
Err(err) => Some(Err(err)),
|
||||
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
ready(return_value)
|
||||
})
|
||||
.boxed()
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"where"
|
||||
}
|
||||
|
||||
fn config(&self) -> CommandConfig {
|
||||
CommandConfig {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![PositionalType::mandatory("condition", SyntaxType::Block)],
|
||||
rest_positional: false,
|
||||
named: IndexMap::default(),
|
||||
is_sink: true,
|
||||
is_filter: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// command! {
|
||||
// Where as where(args, condition: Block,) {
|
||||
// let input = args.input;
|
||||
// let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = input);
|
||||
|
||||
// input.values.filter_map(move |item| {
|
||||
// let result = condition.invoke(&item);
|
||||
|
||||
// let return_value = match result {
|
||||
// Err(err) => Some(Err(err)),
|
||||
// Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
|
||||
// _ => None,
|
||||
// };
|
||||
|
||||
// ready(return_value)
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
122
src/context.rs
122
src/context.rs
@ -1,21 +1,24 @@
|
||||
use crate::commands::command::{CallInfo, Sink, SinkCommandArgs};
|
||||
use crate::commands::command::{CallInfo, Sink, SinkCommandArgs, UnevaluatedCallInfo};
|
||||
use crate::parser::{
|
||||
registry::{Args, CommandConfig, CommandRegistry},
|
||||
hir,
|
||||
registry::{self, CommandConfig},
|
||||
Span,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum SpanSource {
|
||||
Url(String),
|
||||
File(String),
|
||||
Source(Text),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
@ -35,9 +38,51 @@ impl SourceMap {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, new)]
|
||||
pub struct CommandRegistry {
|
||||
#[new(value = "Arc::new(Mutex::new(IndexMap::default()))")]
|
||||
registry: Arc<Mutex<IndexMap<String, Arc<dyn Command>>>>,
|
||||
}
|
||||
|
||||
impl CommandRegistry {
|
||||
crate fn empty() -> CommandRegistry {
|
||||
CommandRegistry {
|
||||
registry: Arc::new(Mutex::new(IndexMap::default())),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_config(&self, name: &str) -> Option<CommandConfig> {
|
||||
let registry = self.registry.lock().unwrap();
|
||||
|
||||
registry.get(name).map(|c| c.config())
|
||||
}
|
||||
|
||||
fn get_command(&self, name: &str) -> Option<Arc<dyn Command>> {
|
||||
let registry = self.registry.lock().unwrap();
|
||||
|
||||
registry.get(name).map(|c| c.clone())
|
||||
}
|
||||
|
||||
fn has(&self, name: &str) -> bool {
|
||||
let registry = self.registry.lock().unwrap();
|
||||
|
||||
registry.contains_key(name)
|
||||
}
|
||||
|
||||
fn insert(&mut self, name: impl Into<String>, command: Arc<dyn Command>) {
|
||||
let mut registry = self.registry.lock().unwrap();
|
||||
registry.insert(name.into(), command);
|
||||
}
|
||||
|
||||
crate fn names(&self) -> Vec<String> {
|
||||
let mut registry = self.registry.lock().unwrap();
|
||||
registry.keys().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
commands: IndexMap<String, Arc<dyn Command>>,
|
||||
registry: CommandRegistry,
|
||||
sinks: IndexMap<String, Arc<dyn Sink>>,
|
||||
crate source_map: SourceMap,
|
||||
crate host: Arc<Mutex<dyn Host + Send>>,
|
||||
@ -45,9 +90,13 @@ pub struct Context {
|
||||
}
|
||||
|
||||
impl Context {
|
||||
crate fn registry(&self) -> &CommandRegistry {
|
||||
&self.registry
|
||||
}
|
||||
|
||||
crate fn basic() -> Result<Context, Box<dyn Error>> {
|
||||
Ok(Context {
|
||||
commands: indexmap::IndexMap::new(),
|
||||
registry: CommandRegistry::new(),
|
||||
sinks: indexmap::IndexMap::new(),
|
||||
source_map: SourceMap::new(),
|
||||
host: Arc::new(Mutex::new(crate::env::host::BasicHost)),
|
||||
@ -57,7 +106,7 @@ impl Context {
|
||||
|
||||
pub fn add_commands(&mut self, commands: Vec<Arc<dyn Command>>) {
|
||||
for command in commands {
|
||||
self.commands.insert(command.name().to_string(), command);
|
||||
self.registry.insert(command.name().to_string(), command);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +132,7 @@ impl Context {
|
||||
&mut self,
|
||||
command: Arc<dyn Sink>,
|
||||
name_span: Option<Span>,
|
||||
args: Args,
|
||||
args: registry::EvaluatedArgs,
|
||||
input: Vec<Spanned<Value>>,
|
||||
) -> Result<(), ShellError> {
|
||||
let command_args = SinkCommandArgs {
|
||||
@ -99,16 +148,16 @@ impl Context {
|
||||
command.run(command_args)
|
||||
}
|
||||
|
||||
pub fn clone_commands(&self) -> indexmap::IndexMap<String, Arc<dyn Command>> {
|
||||
self.commands.clone()
|
||||
pub fn clone_commands(&self) -> CommandRegistry {
|
||||
self.registry.clone()
|
||||
}
|
||||
|
||||
crate fn has_command(&self, name: &str) -> bool {
|
||||
self.commands.contains_key(name)
|
||||
self.registry.has(name)
|
||||
}
|
||||
|
||||
crate fn get_command(&self, name: &str) -> Arc<dyn Command> {
|
||||
self.commands.get(name).unwrap().clone()
|
||||
self.registry.get_command(name).unwrap()
|
||||
}
|
||||
|
||||
crate fn run_command(
|
||||
@ -116,26 +165,43 @@ impl Context {
|
||||
command: Arc<dyn Command>,
|
||||
name_span: Option<Span>,
|
||||
source_map: SourceMap,
|
||||
args: Args,
|
||||
args: hir::Call,
|
||||
source: Text,
|
||||
input: InputStream,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let command_args = CommandArgs {
|
||||
let command_args = self.command_args(args, input, source, source_map, name_span);
|
||||
|
||||
command.run(command_args, self.registry())
|
||||
}
|
||||
|
||||
fn call_info(
|
||||
&self,
|
||||
args: hir::Call,
|
||||
source: Text,
|
||||
source_map: SourceMap,
|
||||
name_span: Option<Span>,
|
||||
) -> UnevaluatedCallInfo {
|
||||
UnevaluatedCallInfo {
|
||||
args,
|
||||
source,
|
||||
source_map,
|
||||
name_span,
|
||||
}
|
||||
}
|
||||
|
||||
fn command_args(
|
||||
&self,
|
||||
args: hir::Call,
|
||||
input: InputStream,
|
||||
source: Text,
|
||||
source_map: SourceMap,
|
||||
name_span: Option<Span>,
|
||||
) -> CommandArgs {
|
||||
CommandArgs {
|
||||
host: self.host.clone(),
|
||||
env: self.env.clone(),
|
||||
call_info: CallInfo {
|
||||
name_span,
|
||||
source_map,
|
||||
args,
|
||||
},
|
||||
call_info: self.call_info(args, source, source_map, name_span),
|
||||
input,
|
||||
};
|
||||
|
||||
command.run(command_args)
|
||||
}
|
||||
}
|
||||
|
||||
impl CommandRegistry for Context {
|
||||
fn get(&self, name: &str) -> Option<CommandConfig> {
|
||||
self.commands.get(name).map(|c| c.config())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
src/env/host.rs
vendored
2
src/env/host.rs
vendored
@ -2,7 +2,7 @@ use crate::prelude::*;
|
||||
use language_reporting::termcolor;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait Host: Debug {
|
||||
pub trait Host: Debug + Send {
|
||||
fn out_terminal(&self) -> Box<term::StdoutTerminal>;
|
||||
fn err_terminal(&self) -> Box<term::StderrTerminal>;
|
||||
|
||||
|
@ -9,7 +9,7 @@ use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
#[derive(new)]
|
||||
crate struct Scope {
|
||||
pub struct Scope {
|
||||
it: Spanned<Value>,
|
||||
#[new(default)]
|
||||
vars: IndexMap<String, Spanned<Value>>,
|
||||
@ -22,16 +22,26 @@ impl Scope {
|
||||
vars: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
crate fn it_value(value: Spanned<Value>) -> Scope {
|
||||
Scope {
|
||||
it: value,
|
||||
vars: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate fn evaluate_baseline_expr(
|
||||
expr: &Expression,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Spanned<Value>, ShellError> {
|
||||
match &expr.item {
|
||||
RawExpression::Literal(literal) => Ok(evaluate_literal(expr.copy_span(*literal), source)),
|
||||
RawExpression::Synthetic(hir::Synthetic::String(s)) => {
|
||||
Ok(Value::string(s).spanned_unknown())
|
||||
}
|
||||
RawExpression::Variable(var) => evaluate_reference(var, scope, source),
|
||||
RawExpression::Binary(binary) => {
|
||||
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
||||
|
@ -23,6 +23,7 @@ mod parser;
|
||||
mod plugin;
|
||||
mod shell;
|
||||
mod stream;
|
||||
mod traits;
|
||||
|
||||
pub use crate::commands::command::{CallInfo, ReturnSuccess, ReturnValue};
|
||||
pub use crate::context::SpanSource;
|
||||
@ -34,4 +35,4 @@ pub use cli::cli;
|
||||
pub use errors::ShellError;
|
||||
pub use object::base::{Primitive, Value};
|
||||
pub use parser::parse::text::Text;
|
||||
pub use parser::registry::{Args, CommandConfig, NamedType, PositionalType};
|
||||
pub use parser::registry::{CommandConfig, EvaluatedArgs, NamedType, PositionalType};
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::errors::ShellError;
|
||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||
use crate::object::SpannedDictBuilder;
|
||||
@ -169,7 +170,12 @@ impl Block {
|
||||
let mut last = None;
|
||||
|
||||
for expr in self.expressions.iter() {
|
||||
last = Some(evaluate_baseline_expr(&expr, &(), &scope, &self.source)?)
|
||||
last = Some(evaluate_baseline_expr(
|
||||
&expr,
|
||||
&CommandRegistry::empty(),
|
||||
&scope,
|
||||
&self.source,
|
||||
)?)
|
||||
}
|
||||
|
||||
Ok(last.unwrap())
|
||||
|
@ -4,9 +4,13 @@ crate mod binary;
|
||||
crate mod named;
|
||||
crate mod path;
|
||||
|
||||
use crate::parser::{Span, Spanned, Unit};
|
||||
use crate::evaluate::Scope;
|
||||
use crate::parser::{registry, Span, Spanned, Unit};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
crate use baseline_parse::{baseline_parse_single_token, baseline_parse_token_as_string};
|
||||
crate use baseline_parse_tokens::{baseline_parse_next_expr, SyntaxType, TokensIterator};
|
||||
@ -23,7 +27,7 @@ pub fn path(head: impl Into<Expression>, tail: Vec<Spanned<impl Into<String>>>)
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Getters, new)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Getters, Serialize, Deserialize, new)]
|
||||
pub struct Call {
|
||||
#[get = "crate"]
|
||||
head: Box<Expression>,
|
||||
@ -33,9 +37,42 @@ pub struct Call {
|
||||
named: Option<NamedArguments>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
impl Call {
|
||||
pub fn evaluate(
|
||||
&self,
|
||||
registry: ®istry::CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<registry::EvaluatedArgs, ShellError> {
|
||||
registry::evaluate_args(self, registry, scope, source)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToDebug for Call {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
write!(f, "({}", self.head.debug(source))?;
|
||||
|
||||
if let Some(positional) = &self.positional {
|
||||
write!(f, " ")?;
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
&itertools::join(positional.iter().map(|p| p.debug(source)), " ")
|
||||
)?;
|
||||
}
|
||||
|
||||
if let Some(named) = &self.named {
|
||||
write!(f, "{}", named.debug(source))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum RawExpression {
|
||||
Literal(Literal),
|
||||
Synthetic(Synthetic),
|
||||
Variable(Variable),
|
||||
Binary(Box<Binary>),
|
||||
Block(Vec<Expression>),
|
||||
@ -45,10 +82,24 @@ pub enum RawExpression {
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum Synthetic {
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl Synthetic {
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
match self {
|
||||
Synthetic::String(_) => "string",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RawExpression {
|
||||
pub fn type_name(&self) -> &'static str {
|
||||
match self {
|
||||
RawExpression::Literal(literal) => literal.type_name(),
|
||||
RawExpression::Synthetic(synthetic) => synthetic.type_name(),
|
||||
RawExpression::Variable(..) => "variable",
|
||||
RawExpression::Binary(..) => "binary",
|
||||
RawExpression::Block(..) => "block",
|
||||
@ -61,36 +112,40 @@ impl RawExpression {
|
||||
pub type Expression = Spanned<RawExpression>;
|
||||
|
||||
impl Expression {
|
||||
fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
|
||||
crate fn int(i: impl Into<i64>, span: impl Into<Span>) -> Expression {
|
||||
Spanned::from_item(RawExpression::Literal(Literal::Integer(i.into())), span)
|
||||
}
|
||||
|
||||
fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
|
||||
crate fn size(i: impl Into<i64>, unit: impl Into<Unit>, span: impl Into<Span>) -> Expression {
|
||||
Spanned::from_item(
|
||||
RawExpression::Literal(Literal::Size(i.into(), unit.into())),
|
||||
span,
|
||||
)
|
||||
}
|
||||
|
||||
fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
crate fn synthetic_string(s: impl Into<String>) -> Expression {
|
||||
RawExpression::Synthetic(Synthetic::String(s.into())).spanned_unknown()
|
||||
}
|
||||
|
||||
crate fn string(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
Spanned::from_item(
|
||||
RawExpression::Literal(Literal::String(inner.into())),
|
||||
outer.into(),
|
||||
)
|
||||
}
|
||||
|
||||
fn bare(span: impl Into<Span>) -> Expression {
|
||||
crate fn bare(span: impl Into<Span>) -> Expression {
|
||||
Spanned::from_item(RawExpression::Literal(Literal::Bare), span.into())
|
||||
}
|
||||
|
||||
fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
crate fn variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
Spanned::from_item(
|
||||
RawExpression::Variable(Variable::Other(inner.into())),
|
||||
outer.into(),
|
||||
)
|
||||
}
|
||||
|
||||
fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
crate fn it_variable(inner: impl Into<Span>, outer: impl Into<Span>) -> Expression {
|
||||
Spanned::from_item(
|
||||
RawExpression::Variable(Variable::It(inner.into())),
|
||||
outer.into(),
|
||||
@ -98,13 +153,37 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToDebug for Expression {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
match self.item() {
|
||||
RawExpression::Literal(l) => write!(f, "{}", l.spanned(self.span()).debug(source)),
|
||||
RawExpression::Synthetic(Synthetic::String(s)) => write!(f, "{:?}", s),
|
||||
RawExpression::Variable(Variable::It(_)) => write!(f, "$it"),
|
||||
RawExpression::Variable(Variable::Other(s)) => write!(f, "${}", s.slice(source)),
|
||||
RawExpression::Binary(b) => write!(f, "{}", b.debug(source)),
|
||||
RawExpression::Block(exprs) => {
|
||||
write!(f, "{{ ")?;
|
||||
|
||||
for expr in exprs {
|
||||
write!(f, "{} ", expr.debug(source))?;
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
RawExpression::Path(p) => write!(f, "{}", p.debug(source)),
|
||||
RawExpression::Boolean(true) => write!(f, "$yes"),
|
||||
RawExpression::Boolean(false) => write!(f, "$no"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Spanned<Path>> for Expression {
|
||||
fn from(path: Spanned<Path>) -> Expression {
|
||||
path.map(|p| RawExpression::Path(Box::new(p)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum Literal {
|
||||
Integer(i64),
|
||||
Size(i64, Unit),
|
||||
@ -112,6 +191,17 @@ pub enum Literal {
|
||||
Bare,
|
||||
}
|
||||
|
||||
impl ToDebug for Spanned<&Literal> {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
match self.item() {
|
||||
Literal::Integer(int) => write!(f, "{}", *int),
|
||||
Literal::Size(int, unit) => write!(f, "{}{:?}", *int, unit),
|
||||
Literal::String(span) => write!(f, "{}", span.slice(source)),
|
||||
Literal::Bare => write!(f, "{}", self.span().slice(source)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
fn type_name(&self) -> &'static str {
|
||||
match self {
|
||||
@ -123,7 +213,7 @@ impl Literal {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
|
||||
pub enum Variable {
|
||||
It(Span),
|
||||
Other(Span),
|
||||
|
@ -12,7 +12,7 @@ use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
pub fn baseline_parse_tokens(
|
||||
token_nodes: &mut TokensIterator<'_>,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<Vec<hir::Expression>, ShellError> {
|
||||
let mut exprs: Vec<hir::Expression> = vec![];
|
||||
@ -43,7 +43,7 @@ pub enum SyntaxType {
|
||||
|
||||
pub fn baseline_parse_next_expr(
|
||||
tokens: &mut TokensIterator,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
syntax_type: SyntaxType,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
@ -176,7 +176,7 @@ pub fn baseline_parse_next_expr(
|
||||
|
||||
pub fn baseline_parse_semantic_token(
|
||||
token: &TokenNode,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
match token {
|
||||
@ -197,7 +197,7 @@ pub fn baseline_parse_semantic_token(
|
||||
|
||||
pub fn baseline_parse_delimited(
|
||||
token: &Spanned<DelimitedNode>,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
match token.delimiter() {
|
||||
@ -216,7 +216,7 @@ pub fn baseline_parse_delimited(
|
||||
|
||||
pub fn baseline_parse_path(
|
||||
token: &Spanned<PathNode>,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<hir::Expression, ShellError> {
|
||||
let head = baseline_parse_semantic_token(token.head(), registry, source)?;
|
||||
|
@ -1,11 +1,26 @@
|
||||
use crate::parser::{hir::Expression, Operator, Spanned};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, new)]
|
||||
#[derive(
|
||||
Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new,
|
||||
)]
|
||||
#[get = "crate"]
|
||||
pub struct Binary {
|
||||
left: Expression,
|
||||
op: Spanned<Operator>,
|
||||
right: Expression,
|
||||
}
|
||||
|
||||
impl ToDebug for Binary {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
write!(f, "{}", self.left.debug(source))?;
|
||||
write!(f, " {} ", self.op.debug(source))?;
|
||||
write!(f, "{}", self.right.debug(source))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
use crate::parser::hir::Expression;
|
||||
use crate::parser::{Flag, Span};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use log::trace;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum NamedValue {
|
||||
AbsentSwitch,
|
||||
PresentSwitch(Span),
|
||||
@ -12,12 +15,27 @@ pub enum NamedValue {
|
||||
Value(Expression),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, new)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, new)]
|
||||
pub struct NamedArguments {
|
||||
#[new(default)]
|
||||
crate named: IndexMap<String, NamedValue>,
|
||||
}
|
||||
|
||||
impl ToDebug for NamedArguments {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
for (name, value) in &self.named {
|
||||
match value {
|
||||
NamedValue::AbsentSwitch => continue,
|
||||
NamedValue::PresentSwitch(span) => write!(f, " {}", span.slice(source))?,
|
||||
NamedValue::AbsentValue => continue,
|
||||
NamedValue::Value(expr) => write!(f, " --{} {}", name, expr.debug(source))?,
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedArguments {
|
||||
pub fn insert_switch(&mut self, name: impl Into<String>, switch: Option<Flag>) {
|
||||
let name = name.into();
|
||||
|
@ -1,10 +1,27 @@
|
||||
use crate::parser::{hir::Expression, Spanned};
|
||||
use crate::prelude::*;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, new)]
|
||||
#[derive(
|
||||
Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Getters, Serialize, Deserialize, new,
|
||||
)]
|
||||
#[get = "crate"]
|
||||
pub struct Path {
|
||||
head: Expression,
|
||||
tail: Vec<Spanned<String>>,
|
||||
}
|
||||
|
||||
impl ToDebug for Path {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result {
|
||||
write!(f, "{}", self.head.debug(source))?;
|
||||
|
||||
for part in &self.tail {
|
||||
write!(f, ".{}", part.item())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::prelude::*;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
|
||||
@ -11,6 +13,12 @@ pub enum Operator {
|
||||
GreaterThanOrEqual,
|
||||
}
|
||||
|
||||
impl ToDebug for Operator {
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, _source: &str) -> fmt::Result {
|
||||
write!(f, "{}", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
#[allow(unused)]
|
||||
pub fn print(&self) -> String {
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::prelude::*;
|
||||
use crate::Text;
|
||||
use derive_new::new;
|
||||
use getset::Getters;
|
||||
@ -14,6 +15,12 @@ pub struct Spanned<T> {
|
||||
pub item: T,
|
||||
}
|
||||
|
||||
impl<T> HasSpan for Spanned<T> {
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Spanned<T> {
|
||||
pub fn spanned(self, span: impl Into<Span>) -> Spanned<T> {
|
||||
Spanned::from_item(self.item, span.into())
|
||||
|
@ -1,3 +1,4 @@
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::Hash;
|
||||
use std::hash::Hasher;
|
||||
@ -202,3 +203,21 @@ where
|
||||
self.partial_cmp(*other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Text {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
self.as_ref().serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deserialize<'de> for Text {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(Text::from(String::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use log::trace;
|
||||
|
||||
pub fn parse_command(
|
||||
config: &CommandConfig,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
call: &Spanned<CallNode>,
|
||||
source: &Text,
|
||||
) -> Result<hir::Call, ShellError> {
|
||||
@ -63,7 +63,7 @@ fn parse_command_head(head: &TokenNode) -> Result<hir::Expression, ShellError> {
|
||||
|
||||
fn parse_command_tail(
|
||||
config: &CommandConfig,
|
||||
registry: &dyn CommandRegistry,
|
||||
registry: &CommandRegistry,
|
||||
tail: Option<Vec<TokenNode>>,
|
||||
source: &Text,
|
||||
command_span: Span,
|
||||
|
@ -1,3 +1,5 @@
|
||||
// TODO: Temporary redirect
|
||||
crate use crate::context::CommandRegistry;
|
||||
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
||||
use crate::parser::{hir, hir::SyntaxType, parse_command, CallNode, Spanned};
|
||||
use crate::prelude::*;
|
||||
@ -80,17 +82,17 @@ pub struct CommandConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, new, Serialize, Deserialize)]
|
||||
pub struct Args {
|
||||
pub struct EvaluatedArgs {
|
||||
pub positional: Option<Vec<Spanned<Value>>>,
|
||||
pub named: Option<IndexMap<String, Spanned<Value>>>,
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct DebugPositional<'a> {
|
||||
pub struct DebugEvaluatedPositional<'a> {
|
||||
positional: &'a Option<Vec<Spanned<Value>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugPositional<'a> {
|
||||
impl fmt::Debug for DebugEvaluatedPositional<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.positional {
|
||||
None => write!(f, "None"),
|
||||
@ -103,11 +105,11 @@ impl fmt::Debug for DebugPositional<'a> {
|
||||
}
|
||||
|
||||
#[derive(new)]
|
||||
pub struct DebugNamed<'a> {
|
||||
pub struct DebugEvaluatedNamed<'a> {
|
||||
named: &'a Option<IndexMap<String, Spanned<Value>>>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugNamed<'a> {
|
||||
impl fmt::Debug for DebugEvaluatedNamed<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.named {
|
||||
None => write!(f, "None"),
|
||||
@ -119,24 +121,27 @@ impl fmt::Debug for DebugNamed<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugArgs<'a> {
|
||||
args: &'a Args,
|
||||
pub struct DebugEvaluatedArgs<'a> {
|
||||
args: &'a EvaluatedArgs,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DebugArgs<'a> {
|
||||
impl fmt::Debug for DebugEvaluatedArgs<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut s = f.debug_struct("Args");
|
||||
|
||||
s.field("positional", &DebugPositional::new(&self.args.positional));
|
||||
s.field("named", &DebugNamed::new(&self.args.named));
|
||||
s.field(
|
||||
"positional",
|
||||
&DebugEvaluatedPositional::new(&self.args.positional),
|
||||
);
|
||||
s.field("named", &DebugEvaluatedNamed::new(&self.args.named));
|
||||
|
||||
s.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn debug(&'a self) -> DebugArgs<'a> {
|
||||
DebugArgs { args: self }
|
||||
impl EvaluatedArgs {
|
||||
pub fn debug(&'a self) -> DebugEvaluatedArgs<'a> {
|
||||
DebugEvaluatedArgs { args: self }
|
||||
}
|
||||
|
||||
pub fn nth(&self, pos: usize) -> Option<&Spanned<Value>> {
|
||||
@ -205,92 +210,17 @@ impl Iterator for PositionalIter<'a> {
|
||||
}
|
||||
|
||||
impl CommandConfig {
|
||||
crate fn evaluate_args(
|
||||
crate fn parse_args(
|
||||
&self,
|
||||
call: &Spanned<CallNode>,
|
||||
registry: &dyn CommandRegistry,
|
||||
scope: &Scope,
|
||||
registry: &CommandRegistry,
|
||||
source: &Text,
|
||||
) -> Result<Args, ShellError> {
|
||||
) -> Result<hir::Call, ShellError> {
|
||||
let args = parse_command(self, registry, call, source)?;
|
||||
|
||||
trace!("parsed args: {:?}", args);
|
||||
|
||||
evaluate_args(args, registry, scope, source)
|
||||
|
||||
// let mut positional: Vec<Spanned<Value>> = vec![];
|
||||
// let mut named: IndexMap<String, Value> = IndexMap::default();
|
||||
|
||||
// let mut args: Vec<TokenNode> = args.cloned().collect();
|
||||
|
||||
// for (key, ty) in self.named.iter() {
|
||||
// let index = args.iter().position(|a| a.is_flag(&key, source));
|
||||
|
||||
// match (index, ty) {
|
||||
// (Some(i), NamedType::Switch) => {
|
||||
// args.remove(i);
|
||||
// named.insert(key.clone(), Value::boolean(true));
|
||||
// }
|
||||
|
||||
// (None, NamedType::Switch) => {}
|
||||
|
||||
// (Some(i), NamedType::Optional(v)) => {
|
||||
// args.remove(i);
|
||||
// named.insert(key.clone(), extract_named(&mut args, i, v)?);
|
||||
// }
|
||||
|
||||
// (None, NamedType::Optional(_)) => {}
|
||||
|
||||
// (Some(i), NamedType::Mandatory(v)) => {
|
||||
// args.remove(i);
|
||||
// named.insert(key.clone(), extract_named(&mut args, i, v)?);
|
||||
// }
|
||||
|
||||
// (None, NamedType::Mandatory(_)) => {
|
||||
// return Err(ShellError::string(&format!(
|
||||
// "Expected mandatory argument {}, but it was missing",
|
||||
// key
|
||||
// )))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// let mut args = args.into_iter();
|
||||
|
||||
// for param in &self.mandatory_positional {
|
||||
// let arg = args.next();
|
||||
|
||||
// let value = match arg {
|
||||
// None => {
|
||||
// return Err(ShellError::string(format!(
|
||||
// "expected mandatory positional argument {}",
|
||||
// param.name()
|
||||
// )))
|
||||
// }
|
||||
|
||||
// Some(arg) => param.evaluate(arg.clone(), scope, source)?,
|
||||
// };
|
||||
|
||||
// positional.push(value);
|
||||
// }
|
||||
|
||||
// if self.rest_positional {
|
||||
// let rest: Result<Vec<Spanned<Value>>, _> = args
|
||||
// .map(|i| evaluate_baseline_expr(&i, &Scope::empty(), source))
|
||||
// .collect();
|
||||
// positional.extend(rest?);
|
||||
// } else {
|
||||
// let rest: Vec<TokenNode> = args.collect();
|
||||
|
||||
// if rest.len() > 0 {
|
||||
// return Err(ShellError::string(&format!(
|
||||
// "Too many arguments, extras: {:?}",
|
||||
// rest
|
||||
// )));
|
||||
// }
|
||||
// }
|
||||
|
||||
// Ok(Args { positional, named })
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
@ -299,25 +229,25 @@ impl CommandConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_args(
|
||||
args: hir::Call,
|
||||
registry: &dyn CommandRegistry,
|
||||
crate fn evaluate_args(
|
||||
call: &hir::Call,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
) -> Result<Args, ShellError> {
|
||||
let positional: Result<Option<Vec<_>>, _> = args
|
||||
) -> Result<EvaluatedArgs, ShellError> {
|
||||
let positional: Result<Option<Vec<_>>, _> = call
|
||||
.positional()
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
p.iter()
|
||||
.map(|e| evaluate_baseline_expr(e, &(), scope, source))
|
||||
.map(|e| evaluate_baseline_expr(e, &CommandRegistry::empty(), scope, source))
|
||||
.collect()
|
||||
})
|
||||
.transpose();
|
||||
|
||||
let positional = positional?;
|
||||
|
||||
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = args
|
||||
let named: Result<Option<IndexMap<String, Spanned<Value>>>, ShellError> = call
|
||||
.named()
|
||||
.as_ref()
|
||||
.map(|n| {
|
||||
@ -348,15 +278,5 @@ fn evaluate_args(
|
||||
|
||||
let named = named?;
|
||||
|
||||
Ok(Args::new(positional, named))
|
||||
}
|
||||
|
||||
pub trait CommandRegistry {
|
||||
fn get(&self, name: &str) -> Option<CommandConfig>;
|
||||
}
|
||||
|
||||
impl CommandRegistry for () {
|
||||
fn get(&self, _name: &str) -> Option<CommandConfig> {
|
||||
None
|
||||
}
|
||||
Ok(EvaluatedArgs::new(positional, named))
|
||||
}
|
||||
|
@ -34,9 +34,10 @@ macro_rules! trace_stream {
|
||||
|
||||
crate use crate::cli::MaybeOwned;
|
||||
crate use crate::commands::command::{
|
||||
Command, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, Sink, SinkCommandArgs,
|
||||
Command, CommandAction, CommandArgs, EvaluatedCommandArgs, ReturnSuccess, ReturnValue, Sink,
|
||||
SinkCommandArgs,
|
||||
};
|
||||
crate use crate::context::Context;
|
||||
crate use crate::context::{CommandRegistry, Context};
|
||||
crate use crate::env::host::handle_unexpected;
|
||||
crate use crate::env::{Environment, Host};
|
||||
crate use crate::errors::ShellError;
|
||||
@ -44,10 +45,10 @@ crate use crate::object::types::ExtractType;
|
||||
crate use crate::object::{Primitive, Value};
|
||||
crate use crate::parser::{Span, Spanned, SpannedItem};
|
||||
crate use crate::stream::{InputStream, OutputStream};
|
||||
crate use crate::traits::{HasSpan, ToDebug};
|
||||
crate use crate::Text;
|
||||
crate use futures::stream::BoxStream;
|
||||
crate use futures::Stream;
|
||||
crate use futures::{FutureExt, StreamExt};
|
||||
crate use futures::{FutureExt, Stream, StreamExt};
|
||||
crate use std::collections::VecDeque;
|
||||
crate use std::future::Future;
|
||||
crate use std::sync::{Arc, Mutex};
|
||||
|
@ -1,4 +1,6 @@
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::prelude::*;
|
||||
|
||||
use derive_new::new;
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::completion::{self, FilenameCompleter};
|
||||
@ -7,7 +9,7 @@ use rustyline::line_buffer::LineBuffer;
|
||||
#[derive(new)]
|
||||
crate struct NuCompleter {
|
||||
pub file_completer: FilenameCompleter,
|
||||
pub commands: indexmap::IndexMap<String, Arc<dyn Command>>,
|
||||
pub commands: CommandRegistry,
|
||||
}
|
||||
|
||||
impl Completer for NuCompleter {
|
||||
@ -19,7 +21,7 @@ impl Completer for NuCompleter {
|
||||
pos: usize,
|
||||
context: &rustyline::Context,
|
||||
) -> rustyline::Result<(usize, Vec<completion::Pair>)> {
|
||||
let commands: Vec<String> = self.commands.keys().cloned().collect();
|
||||
let commands: Vec<String> = self.commands.names();
|
||||
|
||||
let mut completions = self.file_completer.complete(line, pos, context)?.1;
|
||||
|
||||
|
@ -18,7 +18,7 @@ crate struct Helper {
|
||||
}
|
||||
|
||||
impl Helper {
|
||||
crate fn new(commands: indexmap::IndexMap<String, Arc<dyn Command>>) -> Helper {
|
||||
crate fn new(commands: CommandRegistry) -> Helper {
|
||||
Helper {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
|
28
src/traits.rs
Normal file
28
src/traits.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use crate::prelude::*;
|
||||
use std::fmt;
|
||||
|
||||
pub struct Debuggable<'a, T: ToDebug> {
|
||||
inner: &'a T,
|
||||
source: &'a str,
|
||||
}
|
||||
|
||||
impl<T: ToDebug> fmt::Display for Debuggable<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
self.inner.fmt_debug(f, self.source)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HasSpan {
|
||||
fn span(&self) -> Span;
|
||||
}
|
||||
|
||||
pub trait ToDebug: Sized {
|
||||
fn debug(&'a self, source: &'a str) -> Debuggable<'a, Self> {
|
||||
Debuggable {
|
||||
inner: self,
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_debug(&self, f: &mut fmt::Formatter, source: &str) -> fmt::Result;
|
||||
}
|
2
tests/fixtures/nuplayground/.gitignore
vendored
2
tests/fixtures/nuplayground/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
*_test
|
||||
*.txt
|
@ -7,9 +7,9 @@ use std::io::Read;
|
||||
#[macro_export]
|
||||
macro_rules! nu {
|
||||
($out:ident, $cwd:expr, $commands:expr) => {
|
||||
pub use std::error::Error;
|
||||
pub use std::io::prelude::*;
|
||||
pub use std::process::{Command, Stdio};
|
||||
pub use std::error::Error;
|
||||
|
||||
let commands = &*format!(
|
||||
"
|
||||
@ -93,10 +93,11 @@ pub fn setup_playground_for(topic: &str) -> (String, String) {
|
||||
}
|
||||
|
||||
pub fn file_contents(full_path: &str) -> String {
|
||||
let mut file = std::fs::File::open(full_path).expect("can not open file");
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).expect("can not read file");
|
||||
contents
|
||||
let mut file = std::fs::File::open(full_path).expect("can not open file");
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)
|
||||
.expect("can not read file");
|
||||
contents
|
||||
}
|
||||
|
||||
pub fn create_file_at(full_path: &str) {
|
||||
@ -112,7 +113,14 @@ pub fn delete_directory_at(full_path: &str) {
|
||||
}
|
||||
|
||||
pub fn create_directory_at(full_path: &str) {
|
||||
std::fs::create_dir(PathBuf::from(full_path)).expect("can not create directory");
|
||||
let path = PathBuf::from(full_path);
|
||||
|
||||
println!("{:?} - is_dir: {:?}", path, path.is_dir());
|
||||
|
||||
if !path.is_dir() {
|
||||
std::fs::create_dir_all(PathBuf::from(full_path))
|
||||
.expect(&format!("can not create directory {:?}", full_path));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn executable_path() -> PathBuf {
|
||||
|
Loading…
Reference in New Issue
Block a user