forked from extern/nushell
Merge pull request #287 from jonathandturner/more_per_item
Add more support for per-item
This commit is contained in:
commit
7bb62af46f
41
src/cli.rs
41
src/cli.rs
@ -5,7 +5,7 @@ use crate::commands::classified::{
|
||||
};
|
||||
use crate::commands::plugin::JsonRpc;
|
||||
use crate::commands::plugin::{PluginCommand, PluginSink};
|
||||
use crate::commands::static_command;
|
||||
use crate::commands::whole_stream_command;
|
||||
use crate::context::Context;
|
||||
crate use crate::errors::ShellError;
|
||||
use crate::git::current_branch;
|
||||
@ -67,14 +67,14 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
|
||||
if params.is_filter {
|
||||
let fname = fname.to_string();
|
||||
let name = params.name.clone();
|
||||
context.add_commands(vec![static_command(PluginCommand::new(
|
||||
context.add_commands(vec![whole_stream_command(PluginCommand::new(
|
||||
name, fname, params,
|
||||
))]);
|
||||
Ok(())
|
||||
} else {
|
||||
let fname = fname.to_string();
|
||||
let name = params.name.clone();
|
||||
context.add_commands(vec![static_command(PluginSink::new(
|
||||
context.add_commands(vec![whole_stream_command(PluginSink::new(
|
||||
name, fname, params,
|
||||
))]);
|
||||
Ok(())
|
||||
@ -178,25 +178,24 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
command("to-yaml", Box::new(to_yaml::to_yaml)),
|
||||
command("sort-by", Box::new(sort_by::sort_by)),
|
||||
command("tags", Box::new(tags::tags)),
|
||||
static_command(Get),
|
||||
//static_command(Cd),
|
||||
static_command(Remove),
|
||||
static_command(Open),
|
||||
whole_stream_command(Get),
|
||||
per_item_command(Remove),
|
||||
per_item_command(Open),
|
||||
per_item_command(Where),
|
||||
static_command(Config),
|
||||
static_command(SkipWhile),
|
||||
whole_stream_command(Config),
|
||||
whole_stream_command(SkipWhile),
|
||||
per_item_command(Enter),
|
||||
static_command(Exit),
|
||||
static_command(Clip),
|
||||
static_command(Autoview),
|
||||
static_command(Cpy),
|
||||
static_command(Date),
|
||||
static_command(Mkdir),
|
||||
static_command(Move),
|
||||
static_command(Save),
|
||||
static_command(Table),
|
||||
static_command(VTable),
|
||||
static_command(Which),
|
||||
whole_stream_command(Exit),
|
||||
whole_stream_command(Clip),
|
||||
whole_stream_command(Autoview),
|
||||
per_item_command(Cpy),
|
||||
whole_stream_command(Date),
|
||||
per_item_command(Mkdir),
|
||||
per_item_command(Move),
|
||||
whole_stream_command(Save),
|
||||
whole_stream_command(Table),
|
||||
whole_stream_command(VTable),
|
||||
whole_stream_command(Which),
|
||||
]);
|
||||
}
|
||||
let _ = load_plugins(&mut context);
|
||||
@ -356,7 +355,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
_ => pipeline
|
||||
.commands
|
||||
.push(ClassifiedCommand::Internal(InternalCommand {
|
||||
command: static_command(autoview::Autoview),
|
||||
command: whole_stream_command(autoview::Autoview),
|
||||
name_span: Span::unknown(),
|
||||
args: hir::Call::new(
|
||||
Box::new(hir::Expression::synthetic_string("autoview")),
|
||||
|
@ -58,8 +58,8 @@ crate use autoview::Autoview;
|
||||
//crate use cd::Cd;
|
||||
crate use clip::Clip;
|
||||
crate use command::{
|
||||
command, per_item_command, static_command, Command, CommandArgs, PerItemCommand,
|
||||
RawCommandArgs, StaticCommand, UnevaluatedCallInfo,
|
||||
command, per_item_command, whole_stream_command, Command, CommandArgs, PerItemCommand,
|
||||
RawCommandArgs, UnevaluatedCallInfo, WholeStreamCommand,
|
||||
};
|
||||
crate use config::Config;
|
||||
crate use cp::Cpy;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::{RawCommandArgs, StaticCommand};
|
||||
use crate::commands::{RawCommandArgs, WholeStreamCommand};
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -7,7 +7,7 @@ pub struct Autoview;
|
||||
#[derive(Deserialize)]
|
||||
pub struct AutoviewArgs {}
|
||||
|
||||
impl StaticCommand for Autoview {
|
||||
impl WholeStreamCommand for Autoview {
|
||||
fn name(&self) -> &str {
|
||||
"autoview"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::{CommandArgs, StaticCommand};
|
||||
use crate::commands::{CommandArgs, WholeStreamCommand};
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::errors::{labelled, ShellError};
|
||||
use crate::prelude::*;
|
||||
@ -11,7 +11,7 @@ pub struct Clip;
|
||||
#[derive(Deserialize)]
|
||||
pub struct ClipArgs {}
|
||||
|
||||
impl StaticCommand for Clip {
|
||||
impl WholeStreamCommand for Clip {
|
||||
fn name(&self) -> &str {
|
||||
"clip"
|
||||
}
|
||||
|
@ -41,6 +41,33 @@ impl UnevaluatedCallInfo {
|
||||
name_span: self.name_span,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has_it_or_block(&self) -> bool {
|
||||
use hir::RawExpression;
|
||||
use hir::Variable;
|
||||
|
||||
if let Some(positional) = &self.args.positional() {
|
||||
for pos in positional {
|
||||
match pos {
|
||||
Tagged {
|
||||
item: RawExpression::Variable(Variable::It(_)),
|
||||
..
|
||||
} => {
|
||||
return true;
|
||||
}
|
||||
Tagged {
|
||||
item: RawExpression::Block(_),
|
||||
..
|
||||
} => {
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
@ -91,13 +118,13 @@ impl CommandArgs {
|
||||
pub fn evaluate_once(
|
||||
self,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<EvaluatedStaticCommandArgs, ShellError> {
|
||||
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
|
||||
let host = self.host.clone();
|
||||
let shell_manager = self.shell_manager.clone();
|
||||
let input = self.input;
|
||||
let call_info = self.call_info.evaluate(registry, &Scope::empty())?;
|
||||
|
||||
Ok(EvaluatedStaticCommandArgs::new(
|
||||
Ok(EvaluatedWholeStreamCommandArgs::new(
|
||||
host,
|
||||
shell_manager,
|
||||
call_info,
|
||||
@ -217,26 +244,26 @@ impl<T> RunnableRawArgs<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EvaluatedStaticCommandArgs {
|
||||
pub struct EvaluatedWholeStreamCommandArgs {
|
||||
pub args: EvaluatedCommandArgs,
|
||||
pub input: InputStream,
|
||||
}
|
||||
|
||||
impl Deref for EvaluatedStaticCommandArgs {
|
||||
impl Deref for EvaluatedWholeStreamCommandArgs {
|
||||
type Target = EvaluatedCommandArgs;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.args
|
||||
}
|
||||
}
|
||||
|
||||
impl EvaluatedStaticCommandArgs {
|
||||
impl EvaluatedWholeStreamCommandArgs {
|
||||
pub fn new(
|
||||
host: Arc<Mutex<dyn Host>>,
|
||||
shell_manager: ShellManager,
|
||||
call_info: CallInfo,
|
||||
input: impl Into<InputStream>,
|
||||
) -> EvaluatedStaticCommandArgs {
|
||||
EvaluatedStaticCommandArgs {
|
||||
) -> EvaluatedWholeStreamCommandArgs {
|
||||
EvaluatedWholeStreamCommandArgs {
|
||||
args: EvaluatedCommandArgs {
|
||||
host,
|
||||
shell_manager,
|
||||
@ -251,13 +278,13 @@ impl EvaluatedStaticCommandArgs {
|
||||
}
|
||||
|
||||
pub fn parts(self) -> (InputStream, registry::EvaluatedArgs) {
|
||||
let EvaluatedStaticCommandArgs { args, input } = self;
|
||||
let EvaluatedWholeStreamCommandArgs { args, input } = self;
|
||||
|
||||
(input, args.call_info.args)
|
||||
}
|
||||
|
||||
pub fn split(self) -> (InputStream, EvaluatedCommandArgs) {
|
||||
let EvaluatedStaticCommandArgs { args, input } = self;
|
||||
let EvaluatedWholeStreamCommandArgs { args, input } = self;
|
||||
|
||||
(input, args)
|
||||
}
|
||||
@ -386,7 +413,7 @@ impl ReturnSuccess {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StaticCommand: Send + Sync {
|
||||
pub trait WholeStreamCommand: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn run(
|
||||
@ -411,8 +438,9 @@ pub trait PerItemCommand: Send + Sync {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: RawCommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
call_info: &CallInfo,
|
||||
registry: &CommandRegistry,
|
||||
shell_manager: &ShellManager,
|
||||
input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError>;
|
||||
|
||||
@ -428,21 +456,21 @@ pub trait PerItemCommand: Send + Sync {
|
||||
}
|
||||
|
||||
pub enum Command {
|
||||
Static(Arc<dyn StaticCommand>),
|
||||
WholeStream(Arc<dyn WholeStreamCommand>),
|
||||
PerItem(Arc<dyn PerItemCommand>),
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
Command::Static(command) => command.name(),
|
||||
Command::WholeStream(command) => command.name(),
|
||||
Command::PerItem(command) => command.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> Signature {
|
||||
match self {
|
||||
Command::Static(command) => command.signature(),
|
||||
Command::WholeStream(command) => command.signature(),
|
||||
Command::PerItem(command) => command.signature(),
|
||||
}
|
||||
}
|
||||
@ -453,7 +481,7 @@ impl Command {
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
match self {
|
||||
Command::Static(command) => command.run(args, registry),
|
||||
Command::WholeStream(command) => command.run(args, registry),
|
||||
Command::PerItem(command) => self.run_helper(command.clone(), args, registry.clone()),
|
||||
}
|
||||
}
|
||||
@ -469,13 +497,39 @@ impl Command {
|
||||
shell_manager: args.shell_manager,
|
||||
call_info: args.call_info,
|
||||
};
|
||||
|
||||
if raw_args.call_info.has_it_or_block() {
|
||||
let out = args
|
||||
.input
|
||||
.values
|
||||
.map(move |x| command.run(raw_args.clone(), ®istry, x).unwrap())
|
||||
.map(move |x| {
|
||||
let call_info = raw_args
|
||||
.clone()
|
||||
.call_info
|
||||
.evaluate(®istry, &Scope::it_value(x.clone()))
|
||||
.unwrap();
|
||||
match command.run(&call_info, ®istry, &raw_args.shell_manager, x) {
|
||||
Ok(o) => o,
|
||||
Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]),
|
||||
}
|
||||
})
|
||||
.flatten();
|
||||
|
||||
Ok(out.to_output_stream())
|
||||
} else {
|
||||
let nothing = Value::nothing().tagged(Tag::unknown());
|
||||
let call_info = raw_args
|
||||
.clone()
|
||||
.call_info
|
||||
.evaluate(®istry, &Scope::it_value(nothing.clone()))
|
||||
.unwrap();
|
||||
// We don't have an $it or block, so just execute what we have
|
||||
let out = match command.run(&call_info, ®istry, &raw_args.shell_manager, nothing) {
|
||||
Ok(o) => o,
|
||||
Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]),
|
||||
};
|
||||
Ok(out.to_output_stream())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,7 +539,7 @@ pub struct FnFilterCommand {
|
||||
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
}
|
||||
|
||||
impl StaticCommand for FnFilterCommand {
|
||||
impl WholeStreamCommand for FnFilterCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
@ -542,7 +596,7 @@ pub struct FnRawCommand {
|
||||
>,
|
||||
}
|
||||
|
||||
impl StaticCommand for FnRawCommand {
|
||||
impl WholeStreamCommand for FnRawCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
@ -564,14 +618,14 @@ pub fn command(
|
||||
+ Sync,
|
||||
>,
|
||||
) -> Arc<Command> {
|
||||
Arc::new(Command::Static(Arc::new(FnRawCommand {
|
||||
Arc::new(Command::WholeStream(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)))
|
||||
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Arc<Command> {
|
||||
Arc::new(Command::WholeStream(Arc::new(command)))
|
||||
}
|
||||
|
||||
pub fn per_item_command(command: impl PerItemCommand + 'static) -> Arc<Command> {
|
||||
@ -583,7 +637,7 @@ pub fn filter(
|
||||
name: &str,
|
||||
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
|
||||
) -> Arc<Command> {
|
||||
Arc::new(Command::Static(Arc::new(FnFilterCommand {
|
||||
Arc::new(Command::WholeStream(Arc::new(FnFilterCommand {
|
||||
name: name.to_string(),
|
||||
func,
|
||||
})))
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::{config, Value};
|
||||
use crate::parser::hir::SyntaxType;
|
||||
@ -18,7 +18,7 @@ pub struct ConfigArgs {
|
||||
path: Tagged<bool>,
|
||||
}
|
||||
|
||||
impl StaticCommand for Config {
|
||||
impl WholeStreamCommand for Config {
|
||||
fn name(&self) -> &str {
|
||||
"config"
|
||||
}
|
||||
|
@ -7,13 +7,15 @@ use std::path::PathBuf;
|
||||
|
||||
pub struct Cpy;
|
||||
|
||||
impl StaticCommand for Cpy {
|
||||
impl PerItemCommand for Cpy {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
cp(args, registry)
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
shell_manager: &ShellManager,
|
||||
_input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
cp(call_info, shell_manager)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
@ -27,13 +29,16 @@ impl StaticCommand for Cpy {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let mut source = PathBuf::from(args.shell_manager.path());
|
||||
let mut destination = PathBuf::from(args.shell_manager.path());
|
||||
let name_span = args.call_info.name_span;
|
||||
let args = args.evaluate_once(registry)?;
|
||||
pub fn cp(
|
||||
call_info: &CallInfo,
|
||||
shell_manager: &ShellManager,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let mut source = PathBuf::from(shell_manager.path());
|
||||
let mut destination = PathBuf::from(shell_manager.path());
|
||||
let name_span = call_info.name_span;
|
||||
|
||||
match args
|
||||
match call_info
|
||||
.args
|
||||
.nth(0)
|
||||
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||
.as_string()?
|
||||
@ -44,7 +49,8 @@ pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
}
|
||||
}
|
||||
|
||||
match args
|
||||
match call_info
|
||||
.args
|
||||
.nth(1)
|
||||
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||
.as_string()?
|
||||
@ -61,7 +67,7 @@ pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
return Err(ShellError::labeled_error(
|
||||
"Invalid pattern.",
|
||||
"Invalid pattern.",
|
||||
args.nth(0).unwrap().span(),
|
||||
call_info.args.nth(0).unwrap().span(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -69,11 +75,11 @@ pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
|
||||
if sources.len() == 1 {
|
||||
if let Ok(entry) = &sources[0] {
|
||||
if entry.is_dir() && !args.has("recursive") {
|
||||
if entry.is_dir() && !call_info.args.has("recursive") {
|
||||
return Err(ShellError::labeled_error(
|
||||
"is a directory (not copied). Try using \"--recursive\".",
|
||||
"is a directory (not copied). Try using \"--recursive\".",
|
||||
args.nth(0).unwrap().span(),
|
||||
call_info.args.nth(0).unwrap().span(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -242,7 +248,7 @@ pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
return Err(ShellError::labeled_error(
|
||||
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
|
||||
"Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)",
|
||||
args.nth(0).unwrap().span(),
|
||||
call_info.args.nth(0).unwrap().span(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -257,7 +263,7 @@ pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
return Err(ShellError::labeled_error(
|
||||
e.to_string(),
|
||||
e.to_string(),
|
||||
args.nth(0).unwrap().span(),
|
||||
call_info.args.nth(0).unwrap().span(),
|
||||
));
|
||||
}
|
||||
Ok(o) => o,
|
||||
@ -275,10 +281,10 @@ pub fn cp(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
"Copy aborted. (Does {:?} exist?)",
|
||||
&destination.file_name().unwrap()
|
||||
),
|
||||
args.nth(1).unwrap().span(),
|
||||
call_info.args.nth(1).unwrap().span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
Ok(VecDeque::new())
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use crate::object::{Dictionary, Value};
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Local, Utc};
|
||||
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::parser::registry::Signature;
|
||||
use chrono::{Datelike, TimeZone, Timelike};
|
||||
use core::fmt::Display;
|
||||
@ -11,7 +11,7 @@ use indexmap::IndexMap;
|
||||
|
||||
pub struct Date;
|
||||
|
||||
impl StaticCommand for Date {
|
||||
impl WholeStreamCommand for Date {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::commands::command::CommandAction;
|
||||
use crate::commands::{PerItemCommand, RawCommandArgs};
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::evaluate::Scope;
|
||||
use crate::parser::registry;
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -18,15 +17,11 @@ impl PerItemCommand for Enter {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: RawCommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
input: Tagged<Value>,
|
||||
call_info: &CallInfo,
|
||||
_registry: ®istry::CommandRegistry,
|
||||
_shell_manager: &ShellManager,
|
||||
_input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let call_info = args
|
||||
.call_info
|
||||
.evaluate(registry, &Scope::it_value(input))
|
||||
.unwrap();
|
||||
|
||||
match call_info.args.expect_nth(0)? {
|
||||
Tagged {
|
||||
item: Value::Primitive(Primitive::String(location)),
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::commands::command::{CommandAction, StaticCommand};
|
||||
use crate::commands::command::{CommandAction, WholeStreamCommand};
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::registry::{CommandRegistry, Signature};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct Exit;
|
||||
|
||||
impl StaticCommand for Exit {
|
||||
impl WholeStreamCommand for Exit {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
@ -10,7 +10,7 @@ pub struct GetArgs {
|
||||
rest: Vec<Tagged<String>>,
|
||||
}
|
||||
|
||||
impl StaticCommand for Get {
|
||||
impl WholeStreamCommand for Get {
|
||||
fn name(&self) -> &str {
|
||||
"get"
|
||||
}
|
||||
|
@ -6,13 +6,15 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
pub struct Mkdir;
|
||||
|
||||
impl StaticCommand for Mkdir {
|
||||
impl PerItemCommand for Mkdir {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
call_info: &CallInfo,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
mkdir(args, registry)
|
||||
shell_manager: &ShellManager,
|
||||
input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
mkdir(call_info, registry, shell_manager, input)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
@ -24,12 +26,15 @@ impl StaticCommand for Mkdir {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mkdir(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
pub fn mkdir(
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
shell_manager: &ShellManager,
|
||||
_input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let mut full_path = PathBuf::from(shell_manager.path());
|
||||
|
||||
let mut full_path = PathBuf::from(args.shell_manager.path());
|
||||
|
||||
match &args.nth(0) {
|
||||
match &call_info.args.nth(0) {
|
||||
Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)),
|
||||
_ => {}
|
||||
}
|
||||
@ -38,8 +43,8 @@ pub fn mkdir(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStre
|
||||
Err(reason) => Err(ShellError::labeled_error(
|
||||
reason.to_string(),
|
||||
reason.to_string(),
|
||||
args.nth(0).unwrap().span(),
|
||||
call_info.args.nth(0).unwrap().span(),
|
||||
)),
|
||||
Ok(_) => Ok(OutputStream::empty()),
|
||||
Ok(_) => Ok(VecDeque::new()),
|
||||
}
|
||||
}
|
||||
|
@ -9,13 +9,15 @@ use crate::utils::FileStructure;
|
||||
|
||||
pub struct Move;
|
||||
|
||||
impl StaticCommand for Move {
|
||||
impl PerItemCommand for Move {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
mv(args, registry)
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
shell_manager: &ShellManager,
|
||||
_input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
mv(call_info, shell_manager)
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
@ -27,13 +29,16 @@ impl StaticCommand for Move {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let mut source = PathBuf::from(args.shell_manager.path());
|
||||
let mut destination = PathBuf::from(args.shell_manager.path());
|
||||
let span = args.name_span();
|
||||
let args = args.evaluate_once(registry)?;
|
||||
pub fn mv(
|
||||
call_info: &CallInfo,
|
||||
shell_manager: &ShellManager,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let mut source = PathBuf::from(shell_manager.path());
|
||||
let mut destination = PathBuf::from(shell_manager.path());
|
||||
let span = call_info.name_span;
|
||||
|
||||
match args
|
||||
match call_info
|
||||
.args
|
||||
.nth(0)
|
||||
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||
.as_string()?
|
||||
@ -44,7 +49,8 @@ pub fn mv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
}
|
||||
}
|
||||
|
||||
match args
|
||||
match call_info
|
||||
.args
|
||||
.nth(1)
|
||||
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||
.as_string()?
|
||||
@ -61,7 +67,7 @@ pub fn mv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
return Err(ShellError::labeled_error(
|
||||
"Invalid pattern.",
|
||||
"Invalid pattern.",
|
||||
args.nth(0).unwrap().span(),
|
||||
call_info.args.nth(0).unwrap().span(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -227,7 +233,7 @@ pub fn mv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
return Err(ShellError::labeled_error(
|
||||
"Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)",
|
||||
"Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)",
|
||||
args.nth(0).unwrap().span(),
|
||||
call_info.args.nth(0).unwrap().span(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -270,10 +276,10 @@ pub fn mv(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream,
|
||||
"Rename aborted. (Does {:?} exist?)",
|
||||
&destination.file_name().unwrap()
|
||||
),
|
||||
args.nth(1).unwrap().span(),
|
||||
call_info.args.nth(1).unwrap().span(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
Ok(VecDeque::new())
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
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::registry::{self, Signature};
|
||||
use crate::parser::registry::Signature;
|
||||
use crate::prelude::*;
|
||||
use mime::Mime;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -11,13 +10,7 @@ use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
pub struct Open;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct OpenArgs {
|
||||
path: Tagged<PathBuf>,
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
impl StaticCommand for Open {
|
||||
impl PerItemCommand for Open {
|
||||
fn name(&self) -> &str {
|
||||
"open"
|
||||
}
|
||||
@ -30,33 +23,40 @@ impl StaticCommand for Open {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, run)?.run()
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
shell_manager: &ShellManager,
|
||||
_input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
run(call_info, shell_manager)
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
OpenArgs { raw, path }: OpenArgs,
|
||||
RunnableContext {
|
||||
shell_manager,
|
||||
name,
|
||||
..
|
||||
}: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
call_info: &CallInfo,
|
||||
shell_manager: &ShellManager,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let cwd = PathBuf::from(shell_manager.path());
|
||||
let full_path = PathBuf::from(cwd);
|
||||
|
||||
let path_str = path.to_str().ok_or(ShellError::type_error(
|
||||
"Path",
|
||||
"invalid path".tagged(path.tag()),
|
||||
))?;
|
||||
let path = match call_info
|
||||
.args
|
||||
.nth(0)
|
||||
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||
{
|
||||
file => file,
|
||||
};
|
||||
|
||||
let path_str = path.as_string()?;
|
||||
|
||||
let (file_extension, contents, contents_tag, span_source) =
|
||||
fetch(&full_path, path_str, path.span())?;
|
||||
fetch(&full_path, &path_str, path.span())?;
|
||||
|
||||
let file_extension = if raw { None } else { file_extension };
|
||||
let file_extension = if call_info.args.has("raw") {
|
||||
None
|
||||
} else {
|
||||
file_extension
|
||||
};
|
||||
|
||||
let mut stream = VecDeque::new();
|
||||
|
||||
@ -70,7 +70,7 @@ fn run(
|
||||
|
||||
match contents {
|
||||
Value::Primitive(Primitive::String(string)) => {
|
||||
let value = parse_as_value(file_extension, string, contents_tag, name)?;
|
||||
let value = parse_as_value(file_extension, string, contents_tag, call_info.name_span)?;
|
||||
|
||||
match value {
|
||||
Tagged {
|
||||
@ -88,7 +88,7 @@ fn run(
|
||||
other => stream.push_back(ReturnSuccess::value(other.tagged(contents_tag))),
|
||||
};
|
||||
|
||||
Ok(stream.boxed().to_output_stream())
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
pub fn fetch(
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::registry;
|
||||
use crate::prelude::*;
|
||||
@ -41,7 +41,7 @@ pub struct PluginCommand {
|
||||
config: registry::Signature,
|
||||
}
|
||||
|
||||
impl StaticCommand for PluginCommand {
|
||||
impl WholeStreamCommand for PluginCommand {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
@ -239,7 +239,7 @@ pub struct PluginSink {
|
||||
config: registry::Signature,
|
||||
}
|
||||
|
||||
impl StaticCommand for PluginSink {
|
||||
impl WholeStreamCommand for PluginSink {
|
||||
fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::prelude::*;
|
||||
@ -8,13 +7,7 @@ use std::path::PathBuf;
|
||||
|
||||
pub struct Remove;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RemoveArgs {
|
||||
path: Tagged<PathBuf>,
|
||||
recursive: bool,
|
||||
}
|
||||
|
||||
impl StaticCommand for Remove {
|
||||
impl PerItemCommand for Remove {
|
||||
fn name(&self) -> &str {
|
||||
"rm"
|
||||
}
|
||||
@ -27,20 +20,28 @@ impl StaticCommand for Remove {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, rm)?.run()
|
||||
call_info: &CallInfo,
|
||||
_registry: &CommandRegistry,
|
||||
shell_manager: &ShellManager,
|
||||
_input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
rm(call_info, shell_manager)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rm(
|
||||
RemoveArgs { path, recursive }: RemoveArgs,
|
||||
context: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = context.cwd();
|
||||
call_info: &CallInfo,
|
||||
shell_manager: &ShellManager,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let mut full_path = PathBuf::from(shell_manager.path());
|
||||
|
||||
match path.item.to_str().unwrap() {
|
||||
match call_info
|
||||
.args
|
||||
.nth(0)
|
||||
.ok_or_else(|| ShellError::string(&format!("No file or directory specified")))?
|
||||
.as_string()?
|
||||
.as_str()
|
||||
{
|
||||
"." | ".." => return Err(ShellError::string("\".\" and \"..\" may not be removed")),
|
||||
file => full_path.push(file),
|
||||
}
|
||||
@ -57,11 +58,11 @@ pub fn rm(
|
||||
match entry {
|
||||
Ok(path) => {
|
||||
if path.is_dir() {
|
||||
if !recursive {
|
||||
if !call_info.args.has("recursive") {
|
||||
return Err(ShellError::labeled_error(
|
||||
"is a directory",
|
||||
"is a directory",
|
||||
context.name,
|
||||
call_info.name_span,
|
||||
));
|
||||
}
|
||||
std::fs::remove_dir_all(&path).expect("can not remove directory");
|
||||
@ -73,5 +74,5 @@ pub fn rm(
|
||||
}
|
||||
}
|
||||
|
||||
Ok(OutputStream::empty())
|
||||
Ok(VecDeque::new())
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ 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::commands::WholeStreamCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
@ -16,7 +16,7 @@ pub struct SaveArgs {
|
||||
raw: bool,
|
||||
}
|
||||
|
||||
impl StaticCommand for Save {
|
||||
impl WholeStreamCommand for Save {
|
||||
fn name(&self) -> &str {
|
||||
"save"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -9,7 +9,7 @@ pub struct SkipWhileArgs {
|
||||
condition: value::Block,
|
||||
}
|
||||
|
||||
impl StaticCommand for SkipWhile {
|
||||
impl WholeStreamCommand for SkipWhile {
|
||||
fn name(&self) -> &str {
|
||||
"skip-while"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::format::TableView;
|
||||
use crate::prelude::*;
|
||||
@ -11,7 +11,7 @@ pub struct TableArgs {
|
||||
full: bool,
|
||||
}
|
||||
|
||||
impl StaticCommand for Table {
|
||||
impl WholeStreamCommand for Table {
|
||||
fn name(&self) -> &str {
|
||||
"table"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::format::VTableView;
|
||||
use crate::prelude::*;
|
||||
@ -8,7 +8,7 @@ pub struct VTable;
|
||||
#[derive(Deserialize)]
|
||||
pub struct VTableArgs {}
|
||||
|
||||
impl StaticCommand for VTable {
|
||||
impl WholeStreamCommand for VTable {
|
||||
fn name(&self) -> &str {
|
||||
"vtable"
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::{PerItemCommand, RawCommandArgs};
|
||||
use crate::commands::PerItemCommand;
|
||||
use crate::errors::ShellError;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry;
|
||||
@ -17,16 +17,13 @@ impl PerItemCommand for Where {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: RawCommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
call_info: &CallInfo,
|
||||
_registry: ®istry::CommandRegistry,
|
||||
_shell_manager: &ShellManager,
|
||||
input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError> {
|
||||
let input_clone = input.clone();
|
||||
let call_info = args
|
||||
.with_input(vec![input])
|
||||
.evaluate_once(registry)
|
||||
.unwrap();
|
||||
let condition = &call_info.args.call_info.args.positional.unwrap()[0];
|
||||
let condition = call_info.args.expect_nth(0)?;
|
||||
match condition {
|
||||
Tagged {
|
||||
item: Value::Block(block),
|
||||
|
@ -2,12 +2,12 @@ use crate::errors::ShellError;
|
||||
use crate::object::Value;
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::parser::registry::Signature;
|
||||
|
||||
pub struct Which;
|
||||
|
||||
impl StaticCommand for Which {
|
||||
impl WholeStreamCommand for Which {
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
|
@ -295,7 +295,7 @@ crate fn evaluate_args(
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
p.iter()
|
||||
.map(|e| evaluate_baseline_expr(e, &CommandRegistry::empty(), scope, source))
|
||||
.map(|e| evaluate_baseline_expr(e, registry, scope, source))
|
||||
.collect()
|
||||
})
|
||||
.transpose();
|
||||
|
@ -17,8 +17,6 @@ impl Sys {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: add more error checking
|
||||
|
||||
async fn cpu(tag: Tag) -> Option<Tagged<Value>> {
|
||||
if let (Ok(num_cpu), Ok(cpu_speed)) = (
|
||||
heim::cpu::logical_count().await,
|
||||
|
@ -34,9 +34,9 @@ macro_rules! trace_stream {
|
||||
|
||||
crate use crate::cli::MaybeOwned;
|
||||
crate use crate::commands::command::{
|
||||
CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext,
|
||||
CallInfo, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext,
|
||||
};
|
||||
crate use crate::commands::StaticCommand;
|
||||
crate use crate::commands::PerItemCommand;
|
||||
crate use crate::context::CommandRegistry;
|
||||
crate use crate::context::{Context, SpanSource};
|
||||
crate use crate::env::host::handle_unexpected;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
|
||||
use crate::context::SourceMap;
|
||||
use crate::object::dir_entry_dict;
|
||||
use crate::prelude::*;
|
||||
@ -60,7 +60,7 @@ impl Shell for FilesystemShell {
|
||||
"filesystem".to_string()
|
||||
}
|
||||
|
||||
fn ls(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let cwd = self.path.clone();
|
||||
let mut full_path = PathBuf::from(&self.path);
|
||||
match &args.nth(0) {
|
||||
@ -133,7 +133,7 @@ impl Shell for FilesystemShell {
|
||||
Ok(shell_entries.to_output_stream())
|
||||
}
|
||||
|
||||
fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let path = match args.nth(0) {
|
||||
None => match dirs::home_dir() {
|
||||
Some(o) => o,
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
|
||||
use crate::context::SourceMap;
|
||||
use crate::errors::ShellError;
|
||||
use crate::stream::OutputStream;
|
||||
|
||||
pub trait Shell {
|
||||
fn name(&self, source_map: &SourceMap) -> String;
|
||||
fn ls(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError>;
|
||||
fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError>;
|
||||
fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
|
||||
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError>;
|
||||
fn path(&self) -> String;
|
||||
fn set_path(&mut self, path: String);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
|
||||
use crate::errors::ShellError;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::filesystem_shell::FilesystemShell;
|
||||
@ -88,12 +88,12 @@ impl ShellManager {
|
||||
self.set_path(self.path());
|
||||
}
|
||||
|
||||
pub fn ls(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env.last().unwrap().ls(args)
|
||||
}
|
||||
pub fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let env = self.shells.lock().unwrap();
|
||||
|
||||
env.last().unwrap().cd(args)
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::commands::command::EvaluatedStaticCommandArgs;
|
||||
use crate::commands::command::EvaluatedWholeStreamCommandArgs;
|
||||
use crate::context::SourceMap;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::shell::Shell;
|
||||
@ -65,14 +65,14 @@ impl Shell for ValueShell {
|
||||
)
|
||||
}
|
||||
|
||||
fn ls(&self, _args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn ls(&self, _args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
Ok(self
|
||||
.members()
|
||||
.map(|x| ReturnSuccess::value(x))
|
||||
.to_output_stream())
|
||||
}
|
||||
|
||||
fn cd(&self, args: EvaluatedStaticCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let path = match args.nth(0) {
|
||||
None => "/".to_string(),
|
||||
Some(v) => {
|
||||
|
Loading…
Reference in New Issue
Block a user