mirror of
https://github.com/nushell/nushell.git
synced 2025-08-18 01:49:47 +02:00
Restructuring
This commit is contained in:
@@ -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 {
|
||||
|
@@ -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"));
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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: ®istry::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: ®istry::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,
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
@@ -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: ®istry::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());
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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),
|
||||
..
|
||||
|
@@ -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![],
|
||||
|
@@ -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: ®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");
|
||||
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! {
|
||||
|
@@ -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())
|
||||
}
|
||||
|
@@ -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");
|
||||
|
@@ -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))
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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: ®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);
|
||||
|
||||
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())
|
||||
}
|
||||
|
Reference in New Issue
Block a user