Restructuring

This commit is contained in:
Yehuda Katz
2019-08-02 12:15:07 -07:00
parent 73deeb69db
commit fc173c46d8
54 changed files with 1498 additions and 879 deletions

View File

@@ -1,11 +1,31 @@
use crate::commands::command::SinkCommandArgs;
use crate::commands::StaticCommand;
use crate::context::{SourceMap, SpanSource};
use crate::errors::ShellError;
use crate::format::GenericView;
use crate::prelude::*;
use std::path::Path;
pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
pub struct Autoview;
impl StaticCommand for Autoview {
fn name(&self) -> &str {
"autoview"
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
args.process(registry, autoview)?.run()
}
fn signature(&self) -> Signature {
Signature::build("autoview").sink()
}
}
pub fn autoview(args: (), context: RunnableContext) -> Result<OutputStream, ShellError> {
if args.input.len() > 0 {
if let Spanned {
item: Value::Binary(_),
@@ -27,7 +47,7 @@ pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
}
}
Ok(())
Ok(OutputStream::empty())
}
fn equal_shapes(input: &Vec<Spanned<Value>>) -> bool {

View File

@@ -1,27 +1,54 @@
use crate::commands::StaticCommand;
use crate::errors::ShellError;
use crate::prelude::*;
use std::env;
use std::path::PathBuf;
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();
pub struct Cd;
let path = match args.nth(0) {
#[derive(Deserialize)]
pub struct CdArgs {
target: Option<Spanned<PathBuf>>,
}
impl StaticCommand for Cd {
fn name(&self) -> &str {
"cd"
}
fn signature(&self) -> Signature {
Signature::build("cd")
.optional("target", SyntaxType::Path)
.filter()
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
args.process(registry, cd)?.run()
// cd(args, registry)
}
}
pub fn cd(CdArgs { target }: CdArgs, context: RunnableContext) -> Result<OutputStream, ShellError> {
let cwd = context.cwd().to_path_buf();
let path = match &target {
None => match dirs::home_dir() {
Some(o) => o,
_ => {
return Err(ShellError::maybe_labeled_error(
"Can not change to home directory",
"can not go to home",
args.name_span(),
context.name,
))
}
},
Some(v) => {
let target = v.as_string()?;
match dunce::canonicalize(cwd.join(target).as_path()) {
// let target = v.item.as_string()?;
match dunce::canonicalize(cwd.join(&v.item()).as_path()) {
Ok(p) => p,
Err(_) => {
return Err(ShellError::labeled_error(
@@ -38,11 +65,11 @@ pub fn cd(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
match env::set_current_dir(&path) {
Ok(_) => {}
Err(_) => {
if args.len() > 0 {
if let Some(path) = target {
return Err(ShellError::labeled_error(
"Can not change to directory",
"directory not found",
args.nth(0).unwrap().span.clone(),
path.span,
));
} else {
return Err(ShellError::string("Can not change to directory"));

View File

@@ -1,6 +1,5 @@
use crate::commands::command::Sink;
use crate::commands::Command;
use crate::context::SourceMap;
use crate::evaluate::Scope;
use crate::parser::{hir, Span, Spanned, TokenNode};
use crate::prelude::*;
use bytes::{BufMut, BytesMut};
@@ -83,7 +82,6 @@ crate enum ClassifiedCommand {
#[allow(unused)]
Expr(TokenNode),
Internal(InternalCommand),
Sink(SinkCommand),
External(ExternalCommand),
}
@@ -93,34 +91,13 @@ impl ClassifiedCommand {
match self {
ClassifiedCommand::Expr(token) => token.span(),
ClassifiedCommand::Internal(internal) => internal.name_span.into(),
ClassifiedCommand::Sink(sink) => sink.name_span.into(),
ClassifiedCommand::External(external) => external.name_span.into(),
}
}
}
crate struct SinkCommand {
crate command: Arc<dyn Sink>,
crate name_span: Option<Span>,
crate args: hir::Call,
}
impl SinkCommand {
crate fn run(
self,
context: &mut Context,
input: Vec<Spanned<Value>>,
source: &Text,
) -> Result<(), ShellError> {
let args = self
.args
.evaluate(context.registry(), &Scope::empty(), source)?;
context.run_sink(self.command, self.name_span.clone(), args, input)
}
}
crate struct InternalCommand {
crate command: Arc<dyn Command>,
crate command: Arc<Command>,
crate name_span: Option<Span>,
crate source_map: SourceMap,
crate args: hir::Call,
@@ -142,14 +119,16 @@ impl InternalCommand {
let objects: InputStream =
trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects);
let result = context.run_command(
self.command,
self.name_span.clone(),
self.source_map,
self.args,
source,
objects,
)?;
let result = context
.run_command(
self.command,
self.name_span.clone(),
self.source_map,
self.args,
source,
objects,
)
.await?;
let mut result = result.values;

View File

@@ -1,25 +1,71 @@
use crate::commands::command::SinkCommandArgs;
use crate::commands::{CommandArgs, StaticCommand};
use crate::context::CommandRegistry;
use crate::errors::{labelled, ShellError};
use crate::prelude::*;
use clipboard::{ClipboardContext, ClipboardProvider};
use futures::stream::StreamExt;
use futures_async_stream::async_stream_block;
pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
pub struct Clip;
#[derive(Deserialize)]
pub struct ClipArgs {}
impl StaticCommand for Clip {
fn name(&self) -> &str {
"clip"
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
args.process(registry, clip)?.run()
}
fn signature(&self) -> Signature {
Signature::build("clip").sink()
}
}
pub fn clip(
ClipArgs {}: ClipArgs,
RunnableContext { input, name, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
let stream = async_stream_block! {
let values: Vec<Spanned<Value>> = input.values.collect().await;
inner_clip(values, name);
};
let stream: BoxStream<'static, ReturnValue> = stream.boxed();
Ok(OutputStream::from(stream))
}
async fn inner_clip(input: Vec<Spanned<Value>>, name: Option<Span>) -> OutputStream {
let mut clip_context: ClipboardContext = ClipboardProvider::new().unwrap();
let mut new_copy_data = String::new();
if args.input.len() > 0 {
if input.len() > 0 {
let mut first = true;
for i in args.input.iter() {
for i in input.iter() {
if !first {
new_copy_data.push_str("\n");
} else {
first = false;
}
let string = i.as_string().map_err(labelled(
args.name_span(),
let s = i.as_string().map_err(labelled(
name,
"Given non-string data",
"expected strings from pipeline",
))?;
));
let string: String = match s {
Ok(string) => string,
Err(err) => return OutputStream::one(Err(err)),
};
new_copy_data.push_str(&string);
}
@@ -27,5 +73,5 @@ pub fn clip(args: SinkCommandArgs) -> Result<(), ShellError> {
clip_context.set_contents(new_copy_data).unwrap();
Ok(())
OutputStream::empty()
}

View File

@@ -3,8 +3,9 @@ use crate::errors::ShellError;
use crate::evaluate::Scope;
use crate::object::Value;
use crate::parser::hir;
use crate::parser::{registry, Span, Spanned};
use crate::parser::{registry, ConfigDeserializer, Span, Spanned};
use crate::prelude::*;
use derive_new::new;
use getset::Getters;
use serde::{Deserialize, Serialize};
use std::fmt;
@@ -80,6 +81,67 @@ impl CommandArgs {
pub fn name_span(&self) -> Option<Span> {
self.call_info.name_span
}
pub fn process<'de, T: Deserialize<'de>>(
self,
registry: &CommandRegistry,
callback: fn(T, RunnableContext) -> Result<OutputStream, ShellError>,
) -> Result<RunnableArgs<T>, ShellError> {
let env = self.env.clone();
let args = self.evaluate_once(registry)?;
let (input, args) = args.split();
let name_span = args.call_info.name_span;
let mut deserializer = ConfigDeserializer::from_call_node(args);
Ok(RunnableArgs {
args: T::deserialize(&mut deserializer)?,
context: RunnableContext {
input: input,
env,
name: name_span,
},
callback,
})
}
}
pub struct SinkContext {
pub input: Vec<Spanned<Value>>,
pub env: Arc<Mutex<Environment>>,
pub name: Option<Span>,
}
pub struct SinkArgs<T> {
args: T,
context: SinkContext,
callback: fn(T, SinkContext) -> Result<(), ShellError>,
}
pub struct RunnableContext {
pub input: InputStream,
pub env: Arc<Mutex<Environment>>,
pub name: Option<Span>,
}
impl RunnableContext {
pub fn cwd(&self) -> PathBuf {
let env = self.env.clone();
let env = env.lock().unwrap();
env.path.clone()
}
}
pub struct RunnableArgs<T> {
args: T,
context: RunnableContext,
callback: fn(T, RunnableContext) -> Result<OutputStream, ShellError>,
}
impl<T> RunnableArgs<T> {
pub fn run(self) -> Result<OutputStream, ShellError> {
(self.callback)(self.args, self.context)
}
}
pub struct EvaluatedStaticCommandArgs {
@@ -120,6 +182,12 @@ impl EvaluatedStaticCommandArgs {
(input, args.call_info.args)
}
pub fn split(self) -> (InputStream, EvaluatedCommandArgs) {
let EvaluatedStaticCommandArgs { args, input } = self;
(input, args)
}
}
#[derive(Getters)]
@@ -155,7 +223,7 @@ impl EvaluatedFilterCommandArgs {
}
}
#[derive(Getters)]
#[derive(Getters, new)]
#[get = "crate"]
pub struct EvaluatedCommandArgs {
pub host: Arc<Mutex<dyn Host>>,
@@ -184,24 +252,21 @@ impl EvaluatedCommandArgs {
self.call_info.args.get(name)
}
pub fn slice_from(&self, from: usize) -> Vec<Spanned<Value>> {
let positional = &self.call_info.args.positional;
match positional {
None => vec![],
Some(list) => list[from..].to_vec(),
}
}
#[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<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),
@@ -241,38 +306,56 @@ impl ReturnSuccess {
}
}
pub trait Command: Send + Sync {
pub trait StaticCommand: Send + Sync {
fn name(&self) -> &str;
fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError>;
fn name(&self) -> &str;
fn config(&self) -> registry::CommandConfig {
registry::CommandConfig {
fn signature(&self) -> Signature {
Signature {
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;
pub enum Command {
Static(Arc<dyn StaticCommand>),
}
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,
impl Command {
pub fn name(&self) -> &str {
match self {
Command::Static(command) => command.name(),
}
}
pub fn is_sink(&self) -> bool {
match self {
Command::Static(..) => false,
}
}
pub fn signature(&self) -> Signature {
match self {
Command::Static(command) => command.signature(),
}
}
pub async fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError> {
match self {
Command::Static(command) => command.run(args, registry),
}
}
}
@@ -283,7 +366,7 @@ pub struct FnFilterCommand {
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
}
impl Command for FnFilterCommand {
impl StaticCommand for FnFilterCommand {
fn name(&self) -> &str {
&self.name
}
@@ -339,7 +422,11 @@ pub struct FnRawCommand {
>,
}
impl Command for FnRawCommand {
impl StaticCommand for FnRawCommand {
fn name(&self) -> &str {
&self.name
}
fn run(
&self,
args: CommandArgs,
@@ -347,10 +434,6 @@ impl Command for FnRawCommand {
) -> Result<OutputStream, ShellError> {
(self.func)(args, registry)
}
fn name(&self) -> &str {
&self.name
}
}
pub fn command(
@@ -360,45 +443,24 @@ pub fn command(
+ Send
+ Sync,
>,
) -> Arc<dyn Command> {
Arc::new(FnRawCommand {
) -> Arc<Command> {
Arc::new(Command::Static(Arc::new(FnRawCommand {
name: name.to_string(),
func,
})
})))
}
pub fn static_command(command: impl StaticCommand + 'static) -> Arc<Command> {
Arc::new(Command::Static(Arc::new(command)))
}
#[allow(unused)]
pub fn filter(
name: &str,
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
) -> Arc<dyn Command> {
Arc::new(FnFilterCommand {
) -> Arc<Command> {
Arc::new(Command::Static(Arc::new(FnFilterCommand {
name: name.to_string(),
func,
})
}
pub struct FnSink {
name: String,
func: Box<dyn Fn(SinkCommandArgs) -> 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<dyn Fn(SinkCommandArgs) -> Result<(), ShellError>>,
) -> Arc<dyn Sink> {
Arc::new(FnSink {
name: name.to_string(),
func,
})
})))
}

View File

@@ -1,57 +1,61 @@
use crate::prelude::*;
use crate::commands::EvaluatedStaticCommandArgs;
use crate::commands::StaticCommand;
use crate::errors::ShellError;
use crate::object::{config, Value};
use crate::parser::hir::SyntaxType;
use crate::parser::registry::{self, CommandConfig, NamedType};
use indexmap::IndexMap;
use log::trace;
use crate::parser::registry::{self};
use std::iter::FromIterator;
pub struct Config;
impl Command for Config {
#[derive(Deserialize)]
pub struct ConfigArgs {
set: Option<(Spanned<String>, Spanned<Value>)>,
get: Option<Spanned<String>>,
clear: Spanned<bool>,
remove: Option<Spanned<String>>,
path: Spanned<bool>,
}
impl StaticCommand for Config {
fn name(&self) -> &str {
"config"
}
fn signature(&self) -> Signature {
Signature::build("config")
.named("set", SyntaxType::Any)
.named("get", SyntaxType::Any)
.named("remove", SyntaxType::Any)
.switch("clear")
.switch("path")
.sink()
}
fn run(
&self,
args: CommandArgs,
registry: &registry::CommandRegistry,
) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
config(args)
}
fn name(&self) -> &str {
"config"
}
fn config(&self) -> CommandConfig {
let mut named: IndexMap<String, NamedType> = IndexMap::new();
named.insert("set".to_string(), NamedType::Optional(SyntaxType::Any));
named.insert("get".to_string(), NamedType::Optional(SyntaxType::Any));
named.insert("clear".to_string(), NamedType::Switch);
named.insert("remove".to_string(), NamedType::Optional(SyntaxType::Any));
CommandConfig {
name: self.name().to_string(),
positional: vec![],
rest_positional: false,
named,
is_sink: true,
is_filter: false,
}
args.process(registry, config)?.run()
}
}
pub fn config(args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
let mut result = crate::object::config::config(args.name_span())?;
pub fn config(
ConfigArgs {
set,
get,
clear,
remove,
path,
}: ConfigArgs,
RunnableContext { name, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
let mut result = crate::object::config::config(name)?;
trace!("{:#?}", args.call_args().positional);
trace!("{:#?}", args.call_args().named);
if let Some(v) = args.get("get") {
let key = v.as_string()?;
if let Some(v) = get {
let key = v.to_string();
let value = result
.get(&key)
.ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?;
@@ -61,31 +65,38 @@ pub fn config(args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellErr
);
}
if let Some(v) = args.get("set") {
if let Ok((key, value)) = v.as_pair() {
result.insert(key.as_string()?.to_string(), value.clone());
if let Some((key, value)) = set {
result.insert(key.to_string(), value.clone());
config::write_config(&result)?;
config::write_config(&result)?;
return Ok(
stream![Spanned::from_item(Value::Object(result.into()), v.span())]
.from_input_stream(),
);
}
return Ok(stream![Spanned::from_item(
Value::Object(result.into()),
value.span()
)]
.from_input_stream());
}
if let Some(c) = args.get("clear") {
if let Spanned { item: true, span } = clear {
result.clear();
config::write_config(&result)?;
return Ok(
stream![Spanned::from_item(Value::Object(result.into()), c.span())].from_input_stream(),
stream![Spanned::from_item(Value::Object(result.into()), span)].from_input_stream(),
);
}
if let Some(v) = args.get("remove") {
let key = v.as_string()?;
if let Spanned { item: true, span } = path {
let path = config::config_path()?;
return Ok(
stream![Value::Primitive(Primitive::Path(path)).spanned(span)].from_input_stream(),
);
}
if let Some(v) = remove {
let key = v.to_string();
if result.contains_key(&key) {
result.remove(&key);
@@ -96,13 +107,9 @@ pub fn config(args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellErr
)));
}
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).spanned(v)]);
let obj = VecDeque::from_iter(vec![Value::Object(result.into()).spanned(v.span())]);
return Ok(obj.from_input_stream());
}
if args.len() == 0 {
return Ok(vec![Value::Object(result.into()).spanned(args.name_span())].into());
}
Err(ShellError::string(format!("Unimplemented")))
return Ok(vec![Value::Object(result.into()).spanned(name)].into());
}

View File

@@ -2,7 +2,7 @@ use crate::object::base::OF64;
use crate::object::{Primitive, SpannedDictBuilder, Value};
use crate::prelude::*;
fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into<Span>) -> Spanned<Value> {
pub fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into<Span>) -> Spanned<Value> {
let span = span.into();
match v {

View File

@@ -1,9 +1,33 @@
use crate::commands::StaticCommand;
use crate::errors::ShellError;
use crate::object::Value;
use crate::parser::Span;
use crate::prelude::*;
fn get_member(path: &str, span: Span, obj: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
pub struct Get;
#[derive(Deserialize)]
pub struct GetArgs {
rest: Vec<Spanned<String>>,
}
impl StaticCommand for Get {
fn name(&self) -> &str {
"get"
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
args.process(registry, get)?.run()
}
fn signature(&self) -> Signature {
Signature::build("get").rest()
}
}
fn get_member(path: &Spanned<String>, obj: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
let mut current = obj;
for p in path.split(".") {
match current.get_data_by_key(p) {
@@ -12,7 +36,7 @@ fn get_member(path: &str, span: Span, obj: &Spanned<Value>) -> Result<Spanned<Va
return Err(ShellError::labeled_error(
"Unknown field",
"object missing field",
span,
path.span,
));
}
}
@@ -21,42 +45,21 @@ fn get_member(path: &str, span: Span, obj: &Spanned<Value>) -> Result<Spanned<Va
Ok(current.clone())
}
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",
span,
));
}
let amount = args.expect_nth(0)?.as_i64();
let (input, args) = args.parts();
let positional = args.positional;
pub fn get(
GetArgs { rest: fields }: GetArgs,
RunnableContext { input, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
// If it's a number, get the row instead of the column
if let Ok(amount) = amount {
return Ok(input.values.skip(amount as u64).take(1).from_input_stream());
}
let fields: Result<Vec<(String, Span)>, _> = positional
.iter()
.flatten()
.map(|a| (a.as_string().map(|x| (x, a.span))))
.collect();
let fields = fields?;
// if let Some(amount) = amount {
// return Ok(input.values.skip(amount as u64).take(1).from_input_stream());
// }
let stream = input
.values
.map(move |item| {
let mut result = VecDeque::new();
for field in &fields {
match get_member(&field.0, field.1, &item) {
match get_member(field, &item) {
Ok(Spanned {
item: Value::List(l),
..

View File

@@ -12,7 +12,7 @@ macro_rules! command {
Named { $export:tt $args:ident $body:block }
Positional { $($number:tt)* }
Rest {}
CommandConfig {
Signature {
name: $config_name:tt,
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
optional_positional: vec![ $($optional_positional:tt)* ],
@@ -52,8 +52,8 @@ macro_rules! command {
stringify!($config_name)
}
fn config(&self) -> $crate::parser::registry::CommandConfig {
$crate::parser::registry::CommandConfig {
fn config(&self) -> $crate::parser::registry::Signature {
$crate::parser::registry::Signature {
name: self.name().to_string(),
positional: vec![$($mandatory_positional)*],
rest_positional: false,
@@ -82,7 +82,7 @@ macro_rules! command {
Named { $export:tt $args:ident $body:block }
Positional { $($positional_count:tt)* }
Rest { -- $param_name:ident : Switch , $($rest:tt)* }
CommandConfig {
Signature {
name: $config_name:tt,
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
optional_positional: vec![ $($optional_positional:tt)* ],
@@ -102,7 +102,7 @@ macro_rules! command {
Named { $export $args $body }
Positional { $($positional_count)* + 1 }
Rest { $($rest)* }
CommandConfig {
Signature {
name: $config_name,
mandatory_positional: vec![ $($mandatory_positional)* ],
optional_positional: vec![ $($optional_positional)* ],
@@ -132,7 +132,7 @@ macro_rules! command {
Named { $export:tt $args:ident $body:block }
Positional { $($positional_count:tt)* }
Rest { -- $param_name:ident : $param_kind:ty , $($rest:tt)* }
CommandConfig {
Signature {
name: $config_name:tt,
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
optional_positional: vec![ $($optional_positional:tt)* ],
@@ -152,7 +152,7 @@ macro_rules! command {
Named { $export $args $body }
Positional { $($positional_count)* + 1 }
Rest { $($rest)* }
CommandConfig {
Signature {
name: $config_name,
mandatory_positional: vec![ $($mandatory_positional)* ],
optional_positional: vec![ $($optional_positional)* ],
@@ -182,7 +182,7 @@ macro_rules! command {
Named { $export:tt $args:ident $body:block }
Positional { $($positional_count:tt)* }
Rest { -- $param_name:ident ? : $param_kind:ty , $($rest:tt)* }
CommandConfig {
Signature {
name: $config_name:tt,
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
optional_positional: vec![ $($optional_positional:tt)* ],
@@ -202,7 +202,7 @@ macro_rules! command {
Named { $export $args $body }
Positional { $($positional_count)* + 1 }
Rest { $($rest)* }
CommandConfig {
Signature {
name: $config_name,
mandatory_positional: vec![ $($mandatory_positional)* ],
optional_positional: vec![ $($optional_positional)* ],
@@ -232,7 +232,7 @@ macro_rules! command {
Named { $export:ident $args:ident $body:block }
Positional { $($positional_count:tt)* }
Rest { $param_name:ident : Block , $($rest:tt)* }
CommandConfig {
Signature {
name: $config_name:tt,
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
optional_positional: vec![ $($optional_positional:tt)* ],
@@ -255,7 +255,7 @@ macro_rules! command {
Named { $export $args $body }
Positional { $($positional_count)* + 1 }
Rest { $($rest)* }
CommandConfig {
Signature {
name: $config_name,
mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory_block(
stringify!($param_name)
@@ -287,7 +287,7 @@ macro_rules! command {
Named { $export:ident $args:ident $body:block }
Positional { $($positional_count:tt)* }
Rest { $param_name:ident : $param_kind:ty , $($rest:tt)* }
CommandConfig {
Signature {
name: $config_name:tt,
mandatory_positional: vec![ $($mandatory_positional:tt)* ],
optional_positional: vec![ $($optional_positional:tt)* ],
@@ -310,7 +310,7 @@ macro_rules! command {
Named { $export $args $body }
Positional { $($positional_count)* + 1 }
Rest { $($rest)* }
CommandConfig {
Signature {
name: $config_name,
mandatory_positional: vec![ $($mandatory_positional)* $crate::parser::registry::PositionalType::mandatory(
stringify!($param_name), <$param_kind>::syntax_type()
@@ -341,7 +341,7 @@ macro_rules! command {
Named { $export $args $body }
Positional { 0 }
Rest { $($command_rest)* }
CommandConfig {
Signature {
name: $config_name,
mandatory_positional: vec![],
optional_positional: vec![],
@@ -377,11 +377,11 @@ macro_rules! command {
// stringify!($name)
// }
// fn config(&self) -> CommandConfig {
// fn config(&self) -> Signature {
// let mut named: IndexMap<String, NamedType> = IndexMap::new();
// named.insert(stringify!($param).to_string(), NamedType::$kind);
// CommandConfig {
// Signature {
// name: self.name().to_string(),
// mandatory_positional: vec![],
// optional_positional: vec![],

View File

@@ -1,9 +1,10 @@
use crate::commands::StaticCommand;
use crate::context::SpanSource;
use crate::errors::ShellError;
use crate::object::{Primitive, Value};
use crate::parser::hir::SyntaxType;
use crate::parser::parse::span::Span;
use crate::parser::registry::{self, CommandConfig, NamedType};
use crate::parser::registry::{self, Signature};
use crate::prelude::*;
use mime::Mime;
use std::path::{Path, PathBuf};
@@ -12,75 +13,81 @@ use uuid::Uuid;
pub struct Open;
impl Command for Open {
#[derive(Deserialize)]
pub struct OpenArgs {
path: Spanned<PathBuf>,
raw: bool,
}
impl StaticCommand for Open {
fn name(&self) -> &str {
"open"
}
fn signature(&self) -> Signature {
Signature::build(self.name())
.required("path", SyntaxType::Block)
.switch("raw")
.sink()
}
fn run(
&self,
args: CommandArgs,
registry: &registry::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");
args.process(registry, run)?.run()
}
}
let span = args.name_span();
fn run(
OpenArgs { raw, path }: OpenArgs,
RunnableContext { env, name, .. }: RunnableContext,
) -> Result<OutputStream, ShellError> {
let cwd = env.lock().unwrap().path().to_path_buf();
let full_path = PathBuf::from(cwd);
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 { None } else { file_extension };
let file_extension = if raw { None } else { file_extension };
let mut stream = VecDeque::new();
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,
)))
}
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, name)?;
match value {
Spanned {
item: Value::List(list),
..
} => {
for elem in list {
stream.push_back(ReturnSuccess::value(elem));
}
}
x => stream.push_back(ReturnSuccess::value(x)),
}
}
match contents {
Value::Primitive(Primitive::String(string)) => {
let value = parse_as_value(file_extension, string, contents_span, span)?;
other => stream.push_back(ReturnSuccess::value(other.spanned(contents_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))),
};
Ok(stream.boxed().to_output_stream())
}
fn name(&self) -> &str {
"open"
}
fn config(&self) -> CommandConfig {
CommandConfig::new(self.name())
.required("path", SyntaxType::Block)
.named("raw", NamedType::Switch)
.sink()
}
Ok(stream.boxed().to_output_stream())
}
// command! {

View File

@@ -1,7 +1,9 @@
use crate::commands::StaticCommand;
use crate::errors::ShellError;
use crate::parser::registry;
use crate::prelude::*;
use derive_new::new;
use futures_async_stream::async_stream_block;
use serde::{self, Deserialize, Serialize};
use std::io::prelude::*;
use std::io::BufReader;
@@ -37,10 +39,18 @@ pub enum NuResult {
pub struct PluginCommand {
name: String,
path: String,
config: registry::CommandConfig,
config: registry::Signature,
}
impl Command for PluginCommand {
impl StaticCommand for PluginCommand {
fn name(&self) -> &str {
&self.name
}
fn signature(&self) -> registry::Signature {
self.config.clone()
}
fn run(
&self,
args: CommandArgs,
@@ -48,29 +58,36 @@ impl Command for PluginCommand {
) -> Result<OutputStream, ShellError> {
filter_plugin(self.path.clone(), args, registry)
}
fn name(&self) -> &str {
&self.name
}
fn config(&self) -> registry::CommandConfig {
self.config.clone()
}
}
#[derive(new)]
pub struct PluginSink {
name: String,
path: String,
config: registry::CommandConfig,
config: registry::Signature,
}
impl Sink for PluginSink {
fn run(&self, args: SinkCommandArgs) -> Result<(), ShellError> {
sink_plugin(self.path.clone(), args)
impl StaticCommand for PluginSink {
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let path = self.path.clone();
let stream = async_stream_block! {
sink_plugin(path, args).await;
};
let stream: BoxStream<'static, ReturnValue> = stream.boxed();
Ok(OutputStream::from(stream))
}
fn name(&self) -> &str {
&self.name
&self.config.name
}
fn config(&self) -> registry::CommandConfig {
fn signature(&self) -> registry::Signature {
self.config.clone()
}
}
@@ -191,9 +208,10 @@ pub fn filter_plugin(
Ok(stream.to_output_stream())
}
pub fn sink_plugin(path: String, args: SinkCommandArgs) -> Result<(), ShellError> {
pub async fn sink_plugin(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
//use subprocess::Exec;
let request = JsonRpc::new("sink", (args.call_info, args.input));
let input: Vec<Spanned<Value>> = args.input.values.collect().await;
let request = JsonRpc::new("sink", (args.call_info, input));
let request_raw = serde_json::to_string(&request).unwrap();
let mut tmpfile = tempfile::NamedTempFile::new()?;
let _ = writeln!(tmpfile, "{}", request_raw);
@@ -206,5 +224,5 @@ pub fn sink_plugin(path: String, args: SinkCommandArgs) -> Result<(), ShellError
let _ = child.wait();
Ok(())
Ok(OutputStream::empty())
}

View File

@@ -1,63 +1,57 @@
use crate::commands::EvaluatedStaticCommandArgs;
use crate::commands::{EvaluatedStaticCommandArgs, StaticCommand};
use crate::errors::ShellError;
use crate::parser::hir::SyntaxType;
use crate::parser::registry::{CommandConfig, NamedType, PositionalType};
use crate::parser::registry::{NamedType, PositionalType};
use crate::prelude::*;
use indexmap::IndexMap;
use std::path::PathBuf;
pub struct Remove;
impl Command for Remove {
#[derive(Deserialize)]
pub struct RemoveArgs {
path: Spanned<PathBuf>,
recursive: bool,
}
impl StaticCommand for Remove {
fn name(&self) -> &str {
"rm"
}
fn signature(&self) -> Signature {
Signature::build("rm")
.required("path", SyntaxType::Path)
.switch("recursive")
.sink()
}
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 {
"rm"
}
fn config(&self) -> CommandConfig {
let mut named: IndexMap<String, NamedType> = IndexMap::new();
named.insert("recursive".to_string(), NamedType::Switch);
CommandConfig {
name: self.name().to_string(),
positional: vec![PositionalType::mandatory("file", SyntaxType::Path)],
rest_positional: false,
named,
is_sink: true,
is_filter: false,
}
args.process(registry, rm)?.run()
}
}
pub fn rm(
args: EvaluatedStaticCommandArgs,
env: Arc<Mutex<Environment>>,
RemoveArgs { path, recursive }: RemoveArgs,
context: RunnableContext,
) -> Result<OutputStream, ShellError> {
let mut full_path = env.lock().unwrap().path().to_path_buf();
let mut full_path = context.cwd();
match args
.nth(0)
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
.as_string()?
.as_str()
{
match path.item.to_str().unwrap() {
"." | ".." => return Err(ShellError::string("\".\" and \"..\" may not be removed")),
file => full_path.push(file),
}
if full_path.is_dir() {
if !args.has("recursive") {
return Err(ShellError::labeled_error(
if !recursive {
return Err(ShellError::maybe_labeled_error(
"is a directory",
"",
args.name_span().unwrap(),
context.name,
));
}
std::fs::remove_dir_all(&full_path).expect("can not remove directory");

View File

@@ -1,100 +1,119 @@
use crate::commands::command::SinkCommandArgs;
use crate::commands::to_csv::{to_string as to_csv_to_string, value_to_csv_value};
use crate::commands::to_json::value_to_json_value;
use crate::commands::to_toml::value_to_toml_value;
use crate::commands::to_yaml::value_to_yaml_value;
use crate::commands::StaticCommand;
use crate::errors::ShellError;
use crate::object::{Primitive, Value};
use crate::parser::Spanned;
use crate::prelude::*;
use futures_async_stream::async_stream_block;
use std::path::{Path, PathBuf};
pub fn save(args: SinkCommandArgs) -> Result<(), ShellError> {
if args.call_info.args.positional.is_none() {
return Err(ShellError::maybe_labeled_error(
"Save requires a filepath",
"needs path",
args.name_span(),
));
}
pub struct Save;
let positional = match args.call_info.args.positional {
None => return Err(ShellError::string("save requires a filepath")),
Some(p) => p,
};
let cwd = args.ctx.env.lock().unwrap().path().to_path_buf();
let mut full_path = PathBuf::from(cwd);
match &(positional[0].item) {
Value::Primitive(Primitive::String(s)) => full_path.push(Path::new(s)),
_ => {}
}
let save_raw = match positional.get(1) {
Some(Spanned {
item: Value::Primitive(Primitive::String(s)),
..
}) if s == "--raw" => true,
_ => false,
};
let contents = match full_path.extension() {
Some(x) if x == "csv" && !save_raw => {
if args.input.len() != 1 {
return Err(ShellError::string(
"saving to csv requires a single object (or use --raw)",
));
}
to_csv_to_string(&value_to_csv_value(&args.input[0])).unwrap()
}
Some(x) if x == "toml" && !save_raw => {
if args.input.len() != 1 {
return Err(ShellError::string(
"saving to toml requires a single object (or use --raw)",
));
}
toml::to_string(&value_to_toml_value(&args.input[0])).unwrap()
}
Some(x) if x == "json" && !save_raw => {
if args.input.len() != 1 {
return Err(ShellError::string(
"saving to json requires a single object (or use --raw)",
));
}
serde_json::to_string(&value_to_json_value(&args.input[0])).unwrap()
}
Some(x) if x == "yml" && !save_raw => {
if args.input.len() != 1 {
return Err(ShellError::string(
"saving to yml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&args.input[0])).unwrap()
}
Some(x) if x == "yaml" && !save_raw => {
if args.input.len() != 1 {
return Err(ShellError::string(
"saving to yaml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&args.input[0])).unwrap()
}
_ => {
let mut save_data = String::new();
if args.input.len() > 0 {
let mut first = true;
for i in args.input.iter() {
if !first {
save_data.push_str("\n");
} else {
first = false;
}
save_data.push_str(&i.as_string().unwrap());
}
}
save_data
}
};
let _ = std::fs::write(full_path, contents);
Ok(())
#[derive(Deserialize)]
struct SaveArgs {
path: Spanned<PathBuf>,
raw: bool,
}
impl StaticCommand for Save {
fn name(&self) -> &str {
"save"
}
fn signature(&self) -> Signature {
Signature::build("save")
.required("path", SyntaxType::Path)
.switch("raw")
.sink()
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
args.process(registry, save)?.run()
}
}
pub fn save(
SaveArgs {
path,
raw: save_raw,
}: SaveArgs,
context: RunnableContext,
) -> Result<OutputStream, ShellError> {
let mut full_path = context.cwd();
full_path.push(path.item());
let stream = async_stream_block! {
let input: Vec<Spanned<Value>> = context.input.values.collect().await;
let contents = match full_path.extension() {
Some(x) if x == "csv" && !save_raw => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to csv requires a single object (or use --raw)",
));
}
to_csv_to_string(&value_to_csv_value(&input[0])).unwrap()
}
Some(x) if x == "toml" && !save_raw => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to toml requires a single object (or use --raw)",
));
}
toml::to_string(&value_to_toml_value(&input[0])).unwrap()
}
Some(x) if x == "json" && !save_raw => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to json requires a single object (or use --raw)",
));
}
serde_json::to_string(&value_to_json_value(&input[0])).unwrap()
}
Some(x) if x == "yml" && !save_raw => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to yml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
}
Some(x) if x == "yaml" && !save_raw => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to yaml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&input[0])).unwrap()
}
_ => {
let mut save_data = String::new();
if input.len() > 0 {
let mut first = true;
for i in input.iter() {
if !first {
save_data.push_str("\n");
} else {
first = false;
}
save_data.push_str(&i.as_string().unwrap());
}
}
save_data
}
};
let _ = std::fs::write(full_path, contents);
};
let stream: BoxStream<'static, ReturnValue> = stream.boxed();
Ok(OutputStream::from(stream))
}

View File

@@ -1,54 +1,40 @@
use crate::commands::StaticCommand;
use crate::errors::ShellError;
use crate::parser::registry::CommandConfig;
use crate::parser::registry::PositionalType;
use crate::prelude::*;
pub struct SkipWhile;
impl Command for SkipWhile {
#[derive(Deserialize)]
pub struct SkipWhileArgs {
condition: value::Block,
}
impl StaticCommand for SkipWhile {
fn name(&self) -> &str {
"skip-while"
}
fn signature(&self) -> Signature {
Signature::build("skip-while")
.required("condition", SyntaxType::Block)
.filter()
}
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
skip_while(args, registry)
}
fn name(&self) -> &str {
"skip-while"
}
fn config(&self) -> CommandConfig {
CommandConfig {
name: self.name().to_string(),
positional: vec![PositionalType::mandatory_block("condition")],
rest_positional: false,
named: indexmap::IndexMap::new(),
is_filter: true,
is_sink: false,
}
args.process(registry, skip_while)?.run()
}
}
pub fn skip_while(
args: CommandArgs,
registry: &CommandRegistry,
SkipWhileArgs { condition }: SkipWhileArgs,
RunnableContext { input, .. }: RunnableContext,
) -> 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",
span,
));
}
let objects = input.values.skip_while(move |item| {
let result = block.invoke(&item);
let result = condition.invoke(&item);
let return_value = match result {
Ok(v) if v.is_true() => true,

View File

@@ -1,9 +1,8 @@
use crate::commands::command::SinkCommandArgs;
use crate::errors::ShellError;
use crate::format::TableView;
use crate::prelude::*;
pub fn table(args: SinkCommandArgs) -> Result<(), ShellError> {
pub fn table(args: CommandArgs, context: RunnableContext) -> Result<(), ShellError> {
if args.input.len() > 0 {
let mut host = args.ctx.host.lock().unwrap();
let view = TableView::from_list(&args.input);

View File

@@ -1,9 +1,8 @@
use crate::commands::command::SinkCommandArgs;
use crate::errors::ShellError;
use crate::format::VTableView;
use crate::prelude::*;
pub fn vtable(args: SinkCommandArgs) -> Result<(), ShellError> {
pub fn vtable(args: CommandArgs, context: RunnableContext) -> Result<(), ShellError> {
if args.input.len() > 0 {
let mut host = args.ctx.host.lock().unwrap();
let view = VTableView::from_list(&args.input);

View File

@@ -1,75 +1,58 @@
use crate::commands::StaticCommand;
use crate::errors::ShellError;
use crate::object::base as value;
use crate::parser::hir::SyntaxType;
use crate::parser::registry::{self, CommandConfig, PositionalType};
use crate::parser::registry;
use crate::prelude::*;
use futures::future::ready;
use indexmap::IndexMap;
use log::trace;
use serde::Deserialize;
pub struct Where;
impl Command for Where {
#[derive(Deserialize)]
struct WhereArgs {
condition: value::Block,
}
impl StaticCommand for Where {
fn name(&self) -> &str {
"where"
}
fn signature(&self) -> registry::Signature {
Signature::build("where")
.required("condition", SyntaxType::Block)
.sink()
}
fn run(
&self,
args: CommandArgs,
registry: &registry::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);
Ok(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)
})
.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,
}
args.process(registry, run)?.run()
}
}
// command! {
// Where as where(args, condition: Block,) {
// let input = args.input;
// let input: InputStream = trace_stream!(target: "nu::trace_stream::where", "where input" = input);
fn run(
WhereArgs { condition }: WhereArgs,
context: RunnableContext,
) -> Result<OutputStream, ShellError> {
Ok(context
.input
.values
.filter_map(move |item| {
let result = condition.invoke(&item);
// 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,
};
// 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)
// })
// }
// }
ready(return_value)
})
.boxed()
.to_output_stream())
}