mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 16:33:37 +01:00
Merge pull request #285 from jonathandturner/per_item
Add first per-item commands
This commit is contained in:
commit
0b9248cbba
@ -158,7 +158,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
command("cd", Box::new(cd::cd)),
|
||||
command("size", Box::new(size::size)),
|
||||
command("from-yaml", Box::new(from_yaml::from_yaml)),
|
||||
command("enter", Box::new(enter::enter)),
|
||||
//command("enter", Box::new(enter::enter)),
|
||||
command("nth", Box::new(nth::nth)),
|
||||
command("n", Box::new(next::next)),
|
||||
command("p", Box::new(prev::prev)),
|
||||
@ -182,9 +182,10 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
//static_command(Cd),
|
||||
static_command(Remove),
|
||||
static_command(Open),
|
||||
static_command(Where),
|
||||
per_item_command(Where),
|
||||
static_command(Config),
|
||||
static_command(SkipWhile),
|
||||
per_item_command(Enter),
|
||||
static_command(Exit),
|
||||
static_command(Clip),
|
||||
static_command(Autoview),
|
||||
|
@ -57,12 +57,13 @@ crate use autoview::Autoview;
|
||||
//crate use cd::Cd;
|
||||
crate use clip::Clip;
|
||||
crate use command::{
|
||||
command, static_command, Command, CommandArgs, RawCommandArgs, StaticCommand,
|
||||
UnevaluatedCallInfo,
|
||||
command, per_item_command, static_command, Command, CommandArgs, PerItemCommand,
|
||||
RawCommandArgs, StaticCommand, UnevaluatedCallInfo,
|
||||
};
|
||||
crate use config::Config;
|
||||
crate use cp::Copycp;
|
||||
crate use date::Date;
|
||||
crate use enter::Enter;
|
||||
crate use exit::Exit;
|
||||
crate use get::Get;
|
||||
crate use mkdir::Mkdir;
|
||||
|
@ -141,6 +141,9 @@ impl InternalCommand {
|
||||
context.add_span_source(uuid, span_source);
|
||||
}
|
||||
CommandAction::Exit => std::process::exit(0),
|
||||
CommandAction::EnterValueShell(value) => {
|
||||
context.shell_manager.push(Box::new(ValueShell::new(value)));
|
||||
}
|
||||
CommandAction::EnterShell(location) => {
|
||||
let path = std::path::Path::new(&location);
|
||||
|
||||
|
@ -28,7 +28,7 @@ impl ToDebug for UnevaluatedCallInfo {
|
||||
}
|
||||
|
||||
impl UnevaluatedCallInfo {
|
||||
fn evaluate(
|
||||
pub fn evaluate(
|
||||
self,
|
||||
registry: ®istry::CommandRegistry,
|
||||
scope: &Scope,
|
||||
@ -62,7 +62,7 @@ pub struct CommandArgs {
|
||||
pub input: InputStream,
|
||||
}
|
||||
|
||||
#[derive(Getters)]
|
||||
#[derive(Getters, Clone)]
|
||||
#[get = "crate"]
|
||||
pub struct RawCommandArgs {
|
||||
pub host: Arc<Mutex<dyn Host>>,
|
||||
@ -346,6 +346,7 @@ pub enum CommandAction {
|
||||
AddSpanSource(Uuid, SpanSource),
|
||||
Exit,
|
||||
EnterShell(String),
|
||||
EnterValueShell(Tagged<Value>),
|
||||
PreviousShell,
|
||||
NextShell,
|
||||
LeaveShell,
|
||||
@ -405,20 +406,44 @@ pub trait StaticCommand: Send + Sync {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PerItemCommand: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: RawCommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
input: Tagged<Value>,
|
||||
) -> Result<VecDeque<ReturnValue>, ShellError>;
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature {
|
||||
name: self.name().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: true,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Command {
|
||||
Static(Arc<dyn StaticCommand>),
|
||||
PerItem(Arc<dyn PerItemCommand>),
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
Command::Static(command) => command.name(),
|
||||
Command::PerItem(command) => command.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> Signature {
|
||||
match self {
|
||||
Command::Static(command) => command.signature(),
|
||||
Command::PerItem(command) => command.signature(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,8 +454,29 @@ impl Command {
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
match self {
|
||||
Command::Static(command) => command.run(args, registry),
|
||||
Command::PerItem(command) => self.run_helper(command.clone(), args, registry.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn run_helper(
|
||||
&self,
|
||||
command: Arc<dyn PerItemCommand>,
|
||||
args: CommandArgs,
|
||||
registry: CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let raw_args = RawCommandArgs {
|
||||
host: args.host,
|
||||
shell_manager: args.shell_manager,
|
||||
call_info: args.call_info,
|
||||
};
|
||||
let out = args
|
||||
.input
|
||||
.values
|
||||
.map(move |x| command.run(raw_args.clone(), ®istry, x).unwrap())
|
||||
.flatten();
|
||||
|
||||
Ok(out.to_output_stream())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
@ -528,6 +574,10 @@ pub fn static_command(command: impl StaticCommand + 'static) -> Arc<Command> {
|
||||
Arc::new(Command::Static(Arc::new(command)))
|
||||
}
|
||||
|
||||
pub fn per_item_command(command: impl PerItemCommand + 'static) -> Arc<Command> {
|
||||
Arc::new(Command::PerItem(Arc::new(command)))
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn filter(
|
||||
name: &str,
|
||||
|
@ -1,23 +1,46 @@
|
||||
use crate::commands::command::CommandAction;
|
||||
use crate::commands::{PerItemCommand, RawCommandArgs};
|
||||
use crate::errors::ShellError;
|
||||
use crate::evaluate::Scope;
|
||||
use crate::parser::registry;
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn enter(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
|
||||
let args = args.evaluate_once(registry)?;
|
||||
pub struct Enter;
|
||||
|
||||
//TODO: We could also enter a value in the stream
|
||||
if args.len() == 0 {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Enter requires a path",
|
||||
"needs parameter",
|
||||
args.call_info.name_span,
|
||||
));
|
||||
impl PerItemCommand for Enter {
|
||||
fn name(&self) -> &str {
|
||||
"enter"
|
||||
}
|
||||
|
||||
let location = args.expect_nth(0)?.as_string()?;
|
||||
fn signature(&self) -> registry::Signature {
|
||||
Signature::build("enter").required("location", SyntaxType::Block)
|
||||
}
|
||||
|
||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell(
|
||||
location,
|
||||
)))]
|
||||
.into())
|
||||
fn run(
|
||||
&self,
|
||||
args: RawCommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
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)),
|
||||
..
|
||||
} => Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell(
|
||||
location.to_string(),
|
||||
)))]
|
||||
.into()),
|
||||
x => Ok(
|
||||
vec![Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
|
||||
x.clone(),
|
||||
)))]
|
||||
.into(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,12 @@
|
||||
use crate::commands::StaticCommand;
|
||||
use crate::commands::{PerItemCommand, RawCommandArgs};
|
||||
use crate::errors::ShellError;
|
||||
use crate::object::base as value;
|
||||
use crate::parser::hir::SyntaxType;
|
||||
use crate::parser::registry;
|
||||
use crate::prelude::*;
|
||||
|
||||
use futures::future::ready;
|
||||
use serde::Deserialize;
|
||||
|
||||
pub struct Where;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct WhereArgs {
|
||||
condition: value::Block,
|
||||
}
|
||||
|
||||
impl StaticCommand for Where {
|
||||
impl PerItemCommand for Where {
|
||||
fn name(&self) -> &str {
|
||||
"where"
|
||||
}
|
||||
@ -26,31 +17,42 @@ impl StaticCommand for Where {
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
args: CommandArgs,
|
||||
args: RawCommandArgs,
|
||||
registry: ®istry::CommandRegistry,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
args.process(registry, run)?.run()
|
||||
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];
|
||||
match condition {
|
||||
Tagged {
|
||||
item: Value::Block(block),
|
||||
tag,
|
||||
} => {
|
||||
let result = block.invoke(&input_clone);
|
||||
match result {
|
||||
Ok(v) => {
|
||||
if v.is_true() {
|
||||
Ok(VecDeque::from(vec![Ok(ReturnSuccess::Value(input_clone))]))
|
||||
} else {
|
||||
Ok(VecDeque::new())
|
||||
}
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Could not evaluate ({})", e.to_string()),
|
||||
"could not evaluate",
|
||||
tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
Tagged { tag, .. } => Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
"where needs a condition",
|
||||
tag.span,
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
WhereArgs { condition }: WhereArgs,
|
||||
context: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
Ok(context
|
||||
.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())
|
||||
}
|
||||
|
@ -115,7 +115,7 @@ impl Context {
|
||||
self.registry.get_command(name).unwrap()
|
||||
}
|
||||
|
||||
crate async fn run_command(
|
||||
crate async fn run_command<'a>(
|
||||
&mut self,
|
||||
command: Arc<Command>,
|
||||
name_span: Span,
|
||||
|
Loading…
Reference in New Issue
Block a user