Switch to "engine-p" (#3270)

* WIP

* WIP

* first builds

* Tests pass
This commit is contained in:
Jonathan Turner
2021-04-07 04:19:43 +12:00
committed by GitHub
parent ad1c4f5e39
commit 073e5727c6
262 changed files with 2269 additions and 2660 deletions

View File

@ -12,8 +12,8 @@ pub struct UnevaluatedCallInfo {
}
impl UnevaluatedCallInfo {
pub async fn evaluate(self, ctx: &EvaluationContext) -> Result<CallInfo, ShellError> {
let args = evaluate_args(&self.args, ctx).await?;
pub fn evaluate(self, ctx: &EvaluationContext) -> Result<CallInfo, ShellError> {
let args = evaluate_args(&self.args, ctx)?;
Ok(CallInfo {
args,

View File

@ -64,14 +64,14 @@ impl std::fmt::Debug for CommandArgs {
}
impl CommandArgs {
pub async fn evaluate_once(self) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
pub fn evaluate_once(self) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
let ctx = EvaluationContext::from_args(&self);
let host = self.host.clone();
let ctrl_c = self.ctrl_c.clone();
let configs = self.configs.clone();
let shell_manager = self.shell_manager.clone();
let input = self.input;
let call_info = self.call_info.evaluate(&ctx).await?;
let call_info = self.call_info.evaluate(&ctx)?;
let scope = self.scope.clone();
Ok(EvaluatedWholeStreamCommandArgs::new(
@ -85,8 +85,8 @@ impl CommandArgs {
))
}
pub async fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
let args = self.evaluate_once().await?;
pub fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
let args = self.evaluate_once()?;
let call_info = args.call_info.clone();
let mut deserializer = ConfigDeserializer::from_call_info(call_info);

View File

@ -1,8 +1,6 @@
use crate::evaluate::expr::run_expression_block;
use crate::evaluate::internal::run_internal_command;
use crate::evaluation_context::EvaluationContext;
use async_recursion::async_recursion;
use futures::stream::TryStreamExt;
use nu_errors::ShellError;
use nu_parser::ParserScope;
use nu_protocol::hir::{
@ -14,8 +12,7 @@ use nu_stream::InputStream;
use nu_stream::ToOutputStream;
use std::sync::atomic::Ordering;
#[async_recursion]
pub async fn run_block(
pub fn run_block(
block: &Block,
ctx: &EvaluationContext,
mut input: InputStream,
@ -32,34 +29,31 @@ pub async fn run_block(
// Run autoview on the values we've seen so far
// We may want to make this configurable for other kinds of hosting
if let Some(autoview) = ctx.get_command("autoview") {
let mut output_stream = match ctx
.run_command(
autoview,
Tag::unknown(),
Call::new(
Box::new(SpannedExpression::new(
Expression::Synthetic(Synthetic::String("autoview".into())),
Span::unknown(),
)),
let mut output_stream = match ctx.run_command(
autoview,
Tag::unknown(),
Call::new(
Box::new(SpannedExpression::new(
Expression::Synthetic(Synthetic::String("autoview".into())),
Span::unknown(),
),
inp,
)
.await
{
)),
Span::unknown(),
),
inp,
) {
Ok(x) => x,
Err(e) => {
return Err(e);
}
};
match output_stream.try_next().await {
Ok(Some(ReturnSuccess::Value(Value {
match output_stream.next() {
Some(Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(e),
..
}))) => {
return Err(e);
}
Ok(Some(_item)) => {
Some(Ok(_item)) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
@ -68,13 +62,13 @@ pub async fn run_block(
return Ok(InputStream::empty());
}
}
Ok(None) => {
None => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
}
Err(e) => {
Some(Err(e)) => {
return Err(e);
}
}
@ -91,14 +85,14 @@ pub async fn run_block(
Ok(inp) => {
let mut output_stream = inp.to_output_stream();
match output_stream.try_next().await {
Ok(Some(ReturnSuccess::Value(Value {
match output_stream.next() {
Some(Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(e),
..
}))) => {
return Err(e);
}
Ok(Some(_item)) => {
Some(Ok(_item)) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
@ -112,13 +106,13 @@ pub async fn run_block(
return Ok(InputStream::empty());
}
}
Ok(None) => {
None => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
}
Err(e) => {
Some(Err(e)) => {
return Err(e);
}
}
@ -127,7 +121,7 @@ pub async fn run_block(
return Err(e);
}
}
output = run_pipeline(pipeline, ctx, input).await;
output = run_pipeline(pipeline, ctx, input);
input = InputStream::empty();
}
@ -136,8 +130,7 @@ pub async fn run_block(
output
}
#[async_recursion]
async fn run_pipeline(
fn run_pipeline(
commands: &Pipeline,
ctx: &EvaluationContext,
mut input: InputStream,
@ -148,7 +141,7 @@ async fn run_pipeline(
let mut args = vec![];
if let Some(positional) = call.positional {
for pos in &positional {
let result = run_expression_block(pos, ctx).await?.into_vec().await;
let result = run_expression_block(pos, ctx)?.into_vec();
args.push(result);
}
}
@ -159,7 +152,7 @@ async fn run_pipeline(
for (param, value) in block.params.positional.iter().zip(args.iter()) {
ctx.scope.add_var(param.0.name(), value[0].clone());
}
let result = run_block(&block, ctx, input).await;
let result = run_block(&block, ctx, input);
ctx.scope.exit_scope();
let result = result?;
@ -180,7 +173,7 @@ async fn run_pipeline(
{
ctx.scope.add_var(param.0.name(), value[0].clone());
}
let result = run_block(&captured_block.block, ctx, input).await;
let result = run_block(&captured_block.block, ctx, input);
ctx.scope.exit_scope();
let result = result?;
@ -204,11 +197,11 @@ async fn run_pipeline(
}
}
ClassifiedCommand::Expr(expr) => run_expression_block(&*expr, ctx).await?,
ClassifiedCommand::Expr(expr) => run_expression_block(&*expr, ctx)?,
ClassifiedCommand::Error(err) => return Err(err.into()),
ClassifiedCommand::Internal(left) => run_internal_command(left, ctx, input).await?,
ClassifiedCommand::Internal(left) => run_internal_command(left, ctx, input)?,
};
}

View File

@ -5,7 +5,7 @@ use indexmap::IndexMap;
use nu_errors::ShellError;
use nu_protocol::{hir, EvaluatedArgs, UntaggedValue, Value};
pub(crate) async fn evaluate_args(
pub(crate) fn evaluate_args(
call: &hir::Call,
ctx: &EvaluationContext,
) -> Result<EvaluatedArgs, ShellError> {
@ -13,7 +13,7 @@ pub(crate) async fn evaluate_args(
if let Some(positional) = &call.positional {
for pos in positional {
let result = evaluate_baseline_expr(pos, ctx).await?;
let result = evaluate_baseline_expr(pos, ctx)?;
positional_args.push(result);
}
}
@ -33,7 +33,7 @@ pub(crate) async fn evaluate_args(
named_args.insert(name.clone(), UntaggedValue::boolean(true).into_value(tag));
}
hir::NamedValue::Value(_, expr) => {
named_args.insert(name.clone(), evaluate_baseline_expr(expr, ctx).await?);
named_args.insert(name.clone(), evaluate_baseline_expr(expr, ctx)?);
}
_ => {}
};

View File

@ -1,7 +1,6 @@
use crate::evaluate::block::run_block;
use crate::evaluate::operator::apply_operator;
use crate::evaluation_context::EvaluationContext;
use async_recursion::async_recursion;
use indexmap::IndexMap;
use log::trace;
use nu_errors::{ArgumentError, ShellError};
@ -17,8 +16,7 @@ use nu_source::{Span, SpannedItem, Tag};
use nu_stream::InputStream;
use nu_value_ext::ValueExt;
#[async_recursion]
pub async fn evaluate_baseline_expr(
pub fn evaluate_baseline_expr(
expr: &SpannedExpression,
ctx: &EvaluationContext,
) -> Result<Value, ShellError> {
@ -39,12 +37,12 @@ pub async fn evaluate_baseline_expr(
}
Expression::Variable(var, _) => evaluate_reference(&var, ctx, tag),
Expression::Command => unimplemented!(),
Expression::Invocation(block) => evaluate_invocation(block, ctx).await,
Expression::Invocation(block) => evaluate_invocation(block, ctx),
Expression::ExternalCommand(_) => unimplemented!(),
Expression::Binary(binary) => {
// TODO: If we want to add short-circuiting, we'll need to move these down
let left = evaluate_baseline_expr(&binary.left, ctx).await?;
let right = evaluate_baseline_expr(&binary.right, ctx).await?;
let left = evaluate_baseline_expr(&binary.left, ctx)?;
let right = evaluate_baseline_expr(&binary.right, ctx)?;
trace!("left={:?} right={:?}", left.value, right.value);
@ -66,13 +64,13 @@ pub async fn evaluate_baseline_expr(
}
Expression::Range(range) => {
let left = if let Some(left) = &range.left {
evaluate_baseline_expr(&left, ctx).await?
evaluate_baseline_expr(&left, ctx)?
} else {
Value::nothing()
};
let right = if let Some(right) = &range.right {
evaluate_baseline_expr(&right, ctx).await?
evaluate_baseline_expr(&right, ctx)?
} else {
Value::nothing()
};
@ -98,7 +96,7 @@ pub async fn evaluate_baseline_expr(
let mut output_headers = vec![];
for expr in headers {
let val = evaluate_baseline_expr(&expr, ctx).await?;
let val = evaluate_baseline_expr(&expr, ctx)?;
let header = val.as_string()?;
output_headers.push(header);
@ -126,7 +124,7 @@ pub async fn evaluate_baseline_expr(
let mut row_output = IndexMap::new();
for cell in output_headers.iter().zip(row.iter()) {
let val = evaluate_baseline_expr(&cell.1, ctx).await?;
let val = evaluate_baseline_expr(&cell.1, ctx)?;
row_output.insert(cell.0.clone(), val);
}
output_table.push(UntaggedValue::row(row_output).into_value(tag.clone()));
@ -138,7 +136,7 @@ pub async fn evaluate_baseline_expr(
let mut exprs = vec![];
for expr in list {
let expr = evaluate_baseline_expr(&expr, ctx).await?;
let expr = evaluate_baseline_expr(&expr, ctx)?;
exprs.push(expr);
}
@ -165,7 +163,7 @@ pub async fn evaluate_baseline_expr(
)
}
Expression::Path(path) => {
let value = evaluate_baseline_expr(&path.head, ctx).await?;
let value = evaluate_baseline_expr(&path.head, ctx)?;
let mut item = value;
for member in &path.tail {
@ -271,10 +269,7 @@ fn evaluate_reference(name: &str, ctx: &EvaluationContext, tag: Tag) -> Result<V
}
}
async fn evaluate_invocation(
block: &hir::Block,
ctx: &EvaluationContext,
) -> Result<Value, ShellError> {
fn evaluate_invocation(block: &hir::Block, ctx: &EvaluationContext) -> Result<Value, ShellError> {
// FIXME: we should use a real context here
let input = match ctx.scope.get_var("$it") {
Some(it) => InputStream::one(it),
@ -284,9 +279,9 @@ async fn evaluate_invocation(
let mut block = block.clone();
block.set_redirect(ExternalRedirection::Stdout);
let result = run_block(&block, ctx, input).await?;
let result = run_block(&block, ctx, input)?;
let output = result.into_vec().await;
let output = result.into_vec();
if let Some(e) = ctx.get_errors().get(0) {
return Err(e.clone());

View File

@ -3,12 +3,11 @@ use crate::evaluate_baseline_expr;
use log::{log_enabled, trace};
use crate::evaluation_context::EvaluationContext;
use futures::stream::once;
use nu_errors::ShellError;
use nu_protocol::hir::SpannedExpression;
use nu_stream::{InputStream, ToInputStream};
pub(crate) async fn run_expression_block(
pub(crate) fn run_expression_block(
expr: &SpannedExpression,
ctx: &EvaluationContext,
) -> Result<InputStream, ShellError> {
@ -17,7 +16,7 @@ pub(crate) async fn run_expression_block(
trace!(target: "nu::run::expr", "{:?}", expr);
}
let output = evaluate_baseline_expr(expr, ctx).await?;
let output = evaluate_baseline_expr(expr, ctx)?;
Ok(once(async { Ok(output) }).to_input_stream())
Ok(std::iter::once(Ok(output)).to_input_stream())
}

View File

@ -3,16 +3,15 @@ use crate::command_args::RawCommandArgs;
use crate::evaluation_context::EvaluationContext;
use crate::filesystem::filesystem_shell::{FilesystemShell, FilesystemShellMode};
use crate::shell::value_shell::ValueShell;
use futures::StreamExt;
use log::{log_enabled, trace};
use nu_errors::ShellError;
use nu_protocol::hir::{ExternalRedirection, InternalCommand};
use nu_protocol::{CommandAction, ReturnSuccess, UntaggedValue, Value};
use nu_source::{PrettyDebug, Span, Tag};
use nu_stream::{trace_stream, InputStream, ToInputStream};
use nu_stream::{InputStream, ToInputStream};
use std::sync::Arc;
pub(crate) async fn run_internal_command(
pub(crate) fn run_internal_command(
command: InternalCommand,
context: &EvaluationContext,
input: InputStream,
@ -22,19 +21,17 @@ pub(crate) async fn run_internal_command(
trace!(target: "nu::run::internal", "{}", command.name);
}
let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", "input" = input);
let objects: InputStream = input;
let internal_command = context.scope.expect_command(&command.name);
let result = {
context
.run_command(
internal_command?,
Tag::unknown_anchor(command.name_span),
command.args.clone(),
objects,
)
.await?
context.run_command(
internal_command?,
Tag::unknown_anchor(command.name_span),
command.args.clone(),
objects,
)?
};
let head = Arc::new(command.args.head.clone());
@ -43,194 +40,188 @@ pub(crate) async fn run_internal_command(
Ok(InputStream::from_stream(
result
.then(move |item| {
.map(move |item| {
let head = head.clone();
let command = command.clone();
let context = context.clone();
async move {
match item {
Ok(ReturnSuccess::Action(action)) => match action {
CommandAction::ChangePath(path) => {
context.shell_manager.set_path(path);
InputStream::empty()
}
CommandAction::Exit(code) => std::process::exit(code), // TODO: save history.txt
CommandAction::Error(err) => {
context.error(err);
InputStream::empty()
}
CommandAction::AutoConvert(tagged_contents, extension) => {
let contents_tag = tagged_contents.tag.clone();
let command_name = format!("from {}", extension);
let command = command.clone();
if let Some(converter) = context.scope.get_command(&command_name) {
let new_args = RawCommandArgs {
host: context.host.clone(),
ctrl_c: context.ctrl_c.clone(),
configs: context.configs.clone(),
current_errors: context.current_errors.clone(),
shell_manager: context.shell_manager.clone(),
call_info: UnevaluatedCallInfo {
args: nu_protocol::hir::Call {
head: (&*head).clone(),
positional: None,
named: None,
span: Span::unknown(),
external_redirection: ExternalRedirection::Stdout,
},
name_tag: Tag::unknown_anchor(command.name_span),
match item {
Ok(ReturnSuccess::Action(action)) => match action {
CommandAction::ChangePath(path) => {
context.shell_manager.set_path(path);
InputStream::empty()
}
CommandAction::Exit(code) => std::process::exit(code), // TODO: save history.txt
CommandAction::Error(err) => {
context.error(err);
InputStream::empty()
}
CommandAction::AutoConvert(tagged_contents, extension) => {
let contents_tag = tagged_contents.tag.clone();
let command_name = format!("from {}", extension);
let command = command;
if let Some(converter) = context.scope.get_command(&command_name) {
let new_args = RawCommandArgs {
host: context.host.clone(),
ctrl_c: context.ctrl_c.clone(),
configs: context.configs.clone(),
current_errors: context.current_errors.clone(),
shell_manager: context.shell_manager.clone(),
call_info: UnevaluatedCallInfo {
args: nu_protocol::hir::Call {
head: (&*head).clone(),
positional: None,
named: None,
span: Span::unknown(),
external_redirection: ExternalRedirection::Stdout,
},
scope: context.scope.clone(),
};
let result = converter
.run(new_args.with_input(vec![tagged_contents]))
.await;
match result {
Ok(mut result) => {
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
result.drain_vec().await;
let mut output = vec![];
for res in result_vec {
match res {
Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Table(list),
..
})) => {
for l in list {
output.push(Ok(l));
}
}
Ok(ReturnSuccess::Value(Value {
value,
..
})) => {
output
.push(Ok(value
.into_value(contents_tag.clone())));
}
Err(e) => output.push(Err(e)),
_ => {}
}
}
futures::stream::iter(output).to_input_stream()
}
Err(err) => {
context.error(err);
InputStream::empty()
}
}
} else {
InputStream::one(tagged_contents)
}
}
CommandAction::EnterValueShell(value) => {
context
.shell_manager
.insert_at_current(Box::new(ValueShell::new(value)));
InputStream::from_stream(futures::stream::iter(vec![]))
}
CommandAction::EnterShell(location) => {
let mode = if context.shell_manager.is_interactive() {
FilesystemShellMode::Cli
} else {
FilesystemShellMode::Script
};
context.shell_manager.insert_at_current(Box::new(
match FilesystemShell::with_location(location, mode) {
Ok(v) => v,
Err(err) => {
context.error(err.into());
return InputStream::empty();
}
name_tag: Tag::unknown_anchor(command.name_span),
},
));
InputStream::from_stream(futures::stream::iter(vec![]))
}
CommandAction::AddPlugins(path) => {
match crate::plugin::build_plugin::scan(vec![
std::path::PathBuf::from(path),
]) {
Ok(plugins) => {
context.add_commands(
plugins
.into_iter()
.filter(|p| {
!context.is_command_registered(p.name())
})
.collect(),
);
scope: context.scope.clone(),
};
let result =
converter.run(new_args.with_input(vec![tagged_contents]));
InputStream::empty()
match result {
Ok(mut result) => {
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
result.drain_vec();
let mut output = vec![];
for res in result_vec {
match res {
Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Table(list),
..
})) => {
for l in list {
output.push(Ok(l));
}
}
Ok(ReturnSuccess::Value(Value {
value, ..
})) => {
output.push(Ok(
value.into_value(contents_tag.clone())
));
}
Err(e) => output.push(Err(e)),
_ => {}
}
}
output.into_iter().to_input_stream()
}
Err(reason) => {
context.error(reason);
Err(err) => {
context.error(err);
InputStream::empty()
}
}
} else {
InputStream::one(tagged_contents)
}
CommandAction::PreviousShell => {
context.shell_manager.prev();
InputStream::empty()
}
CommandAction::NextShell => {
context.shell_manager.next();
InputStream::empty()
}
CommandAction::LeaveShell(code) => {
context.shell_manager.remove_at_current();
if context.shell_manager.is_empty() {
std::process::exit(code); // TODO: save history.txt
}
CommandAction::EnterValueShell(value) => {
context
.shell_manager
.insert_at_current(Box::new(ValueShell::new(value)));
InputStream::from_stream(std::iter::empty())
}
CommandAction::EnterShell(location) => {
let mode = if context.shell_manager.is_interactive() {
FilesystemShellMode::Cli
} else {
FilesystemShellMode::Script
};
context.shell_manager.insert_at_current(Box::new(
match FilesystemShell::with_location(location, mode) {
Ok(v) => v,
Err(err) => {
context.error(err.into());
return InputStream::empty();
}
},
));
InputStream::from_stream(std::iter::empty())
}
CommandAction::AddPlugins(path) => {
match crate::plugin::build_plugin::scan(vec![std::path::PathBuf::from(
path,
)]) {
Ok(plugins) => {
context.add_commands(
plugins
.into_iter()
.filter(|p| !context.is_command_registered(p.name()))
.collect(),
);
InputStream::empty()
}
InputStream::empty()
}
CommandAction::UnloadConfig(cfg_path) => {
context.unload_config(&cfg_path).await;
InputStream::empty()
}
CommandAction::LoadConfig(cfg_path) => {
if let Err(e) = context.load_config(&cfg_path).await {
InputStream::one(UntaggedValue::Error(e).into_untagged_value())
} else {
Err(reason) => {
context.error(reason);
InputStream::empty()
}
}
},
Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(err),
..
})) => {
context.error(err);
}
CommandAction::PreviousShell => {
context.shell_manager.prev();
InputStream::empty()
}
Ok(ReturnSuccess::Value(v)) => InputStream::one(v),
Ok(ReturnSuccess::DebugValue(v)) => {
let doc = PrettyDebug::pretty_doc(&v);
let mut buffer = termcolor::Buffer::ansi();
let _ = doc.render_raw(
context.with_host(|host| host.width() - 5),
&mut nu_source::TermColored::new(&mut buffer),
);
let value = String::from_utf8_lossy(buffer.as_slice());
InputStream::one(UntaggedValue::string(value).into_untagged_value())
}
Err(err) => {
context.error(err);
CommandAction::NextShell => {
context.shell_manager.next();
InputStream::empty()
}
CommandAction::LeaveShell(code) => {
context.shell_manager.remove_at_current();
if context.shell_manager.is_empty() {
std::process::exit(code); // TODO: save history.txt
}
InputStream::empty()
}
CommandAction::UnloadConfig(cfg_path) => {
context.unload_config(&cfg_path);
InputStream::empty()
}
CommandAction::LoadConfig(cfg_path) => {
if let Err(e) = context.load_config(&cfg_path) {
InputStream::one(UntaggedValue::Error(e).into_untagged_value())
} else {
InputStream::empty()
}
}
},
Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(err),
..
})) => {
context.error(err);
InputStream::empty()
}
Ok(ReturnSuccess::Value(v)) => InputStream::one(v),
Ok(ReturnSuccess::DebugValue(v)) => {
let doc = PrettyDebug::pretty_doc(&v);
let mut buffer = termcolor::Buffer::ansi();
let _ = doc.render_raw(
context.with_host(|host| host.width() - 5),
&mut nu_source::TermColored::new(&mut buffer),
);
let value = String::from_utf8_lossy(buffer.as_slice());
InputStream::one(UntaggedValue::string(value).into_untagged_value())
}
Err(err) => {
context.error(err);
InputStream::empty()
}
}
})
.flatten()
.take_while(|x| futures::future::ready(!x.is_error())),
.take_while(|x| !x.is_error()),
))
}

View File

@ -87,7 +87,7 @@ impl EvaluationContext {
self.scope.has_command(name)
}
pub(crate) async fn run_command(
pub(crate) fn run_command(
&self,
command: Command,
name_tag: Tag,
@ -95,7 +95,7 @@ impl EvaluationContext {
input: InputStream,
) -> Result<OutputStream, ShellError> {
let command_args = self.command_args(args, input, name_tag);
command.run(command_args).await
command.run(command_args)
}
fn call_info(&self, args: hir::Call, name_tag: Tag) -> UnevaluatedCallInfo {
@ -127,7 +127,7 @@ impl EvaluationContext {
// The rational here is that, we should not partially load any config
// that might be damaged. However, startup scripts might fail for various reasons.
// A failure there is not as crucial as wrong config files.
pub async fn load_config(&self, cfg_path: &ConfigPath) -> Result<(), ShellError> {
pub fn load_config(&self, cfg_path: &ConfigPath) -> Result<(), ShellError> {
trace!("Loading cfg {:?}", cfg_path);
let cfg = NuConfig::load(Some(cfg_path.get_path().clone()))?;
@ -178,8 +178,7 @@ impl EvaluationContext {
}
if !startup_scripts.is_empty() {
self.run_scripts(startup_scripts, cfg_path.get_path().parent())
.await;
self.run_scripts(startup_scripts, cfg_path.get_path().parent());
}
Ok(())
@ -189,7 +188,7 @@ impl EvaluationContext {
/// If an error occurs while reloading the config:
/// The config is not reloaded
/// The error is returned
pub async fn reload_config(&self, cfg_path: &ConfigPath) -> Result<(), ShellError> {
pub fn reload_config(&self, cfg_path: &ConfigPath) -> Result<(), ShellError> {
trace!("Reloading cfg {:?}", cfg_path);
let mut configs = self.configs.lock();
@ -263,15 +262,14 @@ impl EvaluationContext {
/// If an error occurs while running exit scripts:
/// The error is added to `self.current_errors`
/// If no config with path of `cfg_path` is present, this method does nothing
pub async fn unload_config(&self, cfg_path: &ConfigPath) {
pub fn unload_config(&self, cfg_path: &ConfigPath) {
trace!("UnLoading cfg {:?}", cfg_path);
let tag = config::cfg_path_to_scope_tag(cfg_path);
//Run exitscripts with scope frame and cfg still applied
if let Some(scripts) = self.scope.get_exitscripts_of_frame_with_tag(&tag) {
self.run_scripts(scripts, cfg_path.get_path().parent())
.await;
self.run_scripts(scripts, cfg_path.get_path().parent());
}
//Unload config
@ -281,10 +279,10 @@ impl EvaluationContext {
/// Runs scripts with cwd of dir. If dir is None, this method does nothing.
/// Each error is added to `self.current_errors`
pub async fn run_scripts(&self, scripts: Vec<String>, dir: Option<&Path>) {
pub fn run_scripts(&self, scripts: Vec<String>, dir: Option<&Path>) {
if let Some(dir) = dir {
for script in scripts {
match script::run_script_in_dir(script.clone(), dir, &self).await {
match script::run_script_in_dir(script.clone(), dir, &self) {
Ok(_) => {}
Err(e) => {
let err = ShellError::untagged_runtime_error(format!(

View File

@ -1,25 +1,21 @@
use crate::command_args::EvaluatedWholeStreamCommandArgs;
use crate::filesystem::dir_info::{DirBuilder, DirInfo};
use crate::filesystem::path::canonicalize;
use crate::filesystem::utils::FileStructure;
use crate::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
use crate::shell::shell_args::{CdArgs, CopyArgs, LsArgs, MkdirArgs, MvArgs, RemoveArgs};
use crate::shell::Shell;
use crate::{command_args::EvaluatedWholeStreamCommandArgs, BufCodecReader};
use encoding_rs::Encoding;
use futures::stream::BoxStream;
use futures::StreamExt;
use futures_codec::FramedRead;
use futures_util::TryStreamExt;
use nu_data::config::LocalConfigDiff;
use nu_protocol::{CommandAction, ConfigPath, TaggedDictBuilder, Value};
use nu_source::{Span, Tag};
use nu_stream::{Interruptible, OutputStream, ToOutputStream};
use std::collections::HashMap;
use std::collections::VecDeque;
use std::io::{Error, ErrorKind};
use std::path::{Path, PathBuf};
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::{collections::HashMap, io::BufReader};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
@ -183,49 +179,50 @@ impl Shell for FilesystemShell {
// Generated stream: impl Stream<Item = Result<ReturnSuccess, ShellError>
Ok(futures::stream::iter(paths.filter_map(move |path| {
let path = match path.map_err(|e| ShellError::from(e.into_error())) {
Ok(path) => path,
Err(err) => return Some(Err(err)),
};
Ok(paths
.filter_map(move |path| {
let path = match path.map_err(|e| ShellError::from(e.into_error())) {
Ok(path) => path,
Err(err) => return Some(Err(err)),
};
if path_contains_hidden_folder(&path, &hidden_dirs) {
return None;
}
if !all && !hidden_dir_specified && is_hidden_dir(&path) {
if path.is_dir() {
hidden_dirs.push(path);
if path_contains_hidden_folder(&path, &hidden_dirs) {
return None;
}
return None;
}
let metadata = match std::fs::symlink_metadata(&path) {
Ok(metadata) => Some(metadata),
Err(e) => {
if e.kind() == ErrorKind::PermissionDenied || e.kind() == ErrorKind::Other {
None
} else {
return Some(Err(e.into()));
if !all && !hidden_dir_specified && is_hidden_dir(&path) {
if path.is_dir() {
hidden_dirs.push(path);
}
return None;
}
};
let entry = dir_entry_dict(
&path,
metadata.as_ref(),
name_tag.clone(),
long,
short_names,
du,
ctrl_c.clone(),
)
.map(ReturnSuccess::Value);
let metadata = match std::fs::symlink_metadata(&path) {
Ok(metadata) => Some(metadata),
Err(e) => {
if e.kind() == ErrorKind::PermissionDenied || e.kind() == ErrorKind::Other {
None
} else {
return Some(Err(e.into()));
}
}
};
Some(entry)
}))
.interruptible(ctrl_c_copy)
.to_output_stream())
let entry = dir_entry_dict(
&path,
metadata.as_ref(),
name_tag.clone(),
long,
short_names,
du,
ctrl_c.clone(),
)
.map(ReturnSuccess::Value);
Some(entry)
})
.interruptible(ctrl_c_copy)
.to_output_stream())
}
fn cd(&self, args: CdArgs, name: Tag) -> Result<OutputStream, ShellError> {
@ -665,8 +662,9 @@ impl Shell for FilesystemShell {
));
}
Ok(
futures::stream::iter(all_targets.into_iter().map(move |(f, tag)| {
Ok(all_targets
.into_iter()
.map(move |(f, tag)| {
let is_empty = || match f.read_dir() {
Ok(mut p) => p.next().is_none(),
Err(_) => false,
@ -741,9 +739,8 @@ impl Shell for FilesystemShell {
tag,
))
}
}))
.to_output_stream(),
)
})
.to_output_stream())
}
fn path(&self) -> String {
@ -794,7 +791,10 @@ impl Shell for FilesystemShell {
path: &Path,
name: Span,
with_encoding: Option<&'static Encoding>,
) -> Result<BoxStream<'static, Result<StringOrBinary, ShellError>>, ShellError> {
) -> Result<
Box<dyn Iterator<Item = Result<StringOrBinary, ShellError>> + Sync + Send>,
ShellError,
> {
let metadata = std::fs::metadata(&path);
let read_full = if let Ok(metadata) = metadata {
@ -805,8 +805,6 @@ impl Shell for FilesystemShell {
};
if read_full {
use futures_codec::Decoder;
// We should, in theory, be able to read in the whole file as one chunk
let buffer = std::fs::read(&path).map_err(|e| {
ShellError::labeled_error(
@ -816,15 +814,15 @@ impl Shell for FilesystemShell {
)
})?;
let mut bytes_mut = bytes::BytesMut::from(&buffer[..]);
let bytes_mut = bytes::BytesMut::from(&buffer[..]);
let mut codec = MaybeTextCodec::new(with_encoding);
match codec.decode(&mut bytes_mut).map_err(|_| {
match codec.decode(&bytes_mut).map_err(|_| {
ShellError::labeled_error("Error opening file", "error opening file", name)
})? {
Some(sb) => Ok(futures::stream::iter(vec![Ok(sb)].into_iter()).boxed()),
None => Ok(futures::stream::iter(vec![].into_iter()).boxed()),
Some(sb) => Ok(Box::new(vec![Ok(sb)].into_iter())),
None => Ok(Box::new(vec![].into_iter())),
}
} else {
// We don't know that this is a finite file, so treat it as a stream
@ -835,14 +833,10 @@ impl Shell for FilesystemShell {
name,
)
})?;
let async_reader = futures::io::AllowStdIo::new(f);
let sob_stream = FramedRead::new(async_reader, MaybeTextCodec::new(with_encoding))
.map_err(move |_| {
ShellError::labeled_error("Error opening file", "error opening file", name)
})
.into_stream();
let buf_reader = BufReader::new(f);
let buf_codec = BufCodecReader::new(buf_reader, MaybeTextCodec::new(with_encoding));
Ok(sob_stream.boxed())
Ok(Box::new(buf_codec))
}
}

View File

@ -36,7 +36,7 @@ pub use crate::example::Example;
pub use crate::filesystem::dir_info::{DirBuilder, DirInfo, FileInfo};
pub use crate::filesystem::filesystem_shell::FilesystemShell;
pub use crate::filesystem::path;
pub use crate::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
pub use crate::maybe_text_codec::{BufCodecReader, MaybeTextCodec, StringOrBinary};
pub use crate::print::maybe_print_errors;
pub use crate::runnable_context::RunnableContext;
pub use crate::shell::painter::Painter;

View File

@ -1,4 +1,4 @@
use bytes::{BufMut, Bytes, BytesMut};
use std::io::{BufRead, BufReader, Read};
use nu_errors::ShellError;
@ -19,6 +19,39 @@ pub struct MaybeTextCodec {
decoder: Decoder,
}
pub struct BufCodecReader<R: Read> {
maybe_text_codec: MaybeTextCodec,
input: BufReader<R>,
}
impl<R: Read> BufCodecReader<R> {
pub fn new(input: BufReader<R>, maybe_text_codec: MaybeTextCodec) -> Self {
BufCodecReader {
input,
maybe_text_codec,
}
}
}
impl<R: Read> Iterator for BufCodecReader<R> {
type Item = Result<StringOrBinary, ShellError>;
fn next(&mut self) -> Option<Self::Item> {
let buffer = self.input.fill_buf();
match buffer {
Ok(s) => {
let result = self.maybe_text_codec.decode(&s).transpose();
let buffer_len = s.len();
self.input.consume(buffer_len);
result
}
Err(e) => Some(Err(ShellError::untagged_runtime_error(e.to_string()))),
}
}
}
impl MaybeTextCodec {
// The constructor takes an Option<&'static Encoding>, because an absence of an encoding indicates that we want BOM sniffing enabled
pub fn new(encoding: Option<&'static Encoding>) -> Self {
@ -38,31 +71,21 @@ impl Default for MaybeTextCodec {
}
}
impl futures_codec::Encoder for MaybeTextCodec {
type Item = StringOrBinary;
type Error = std::io::Error;
// impl MaybeTextCodec {
// fn encode(&mut self, item: StringOrBinary, mut dst: &mut [u8]) {
// match item {
// StringOrBinary::String(s) => {
// dst.put(s.as_bytes());
// }
// StringOrBinary::Binary(b) => {
// dst.put(Bytes::from(b));
// }
// }
// }
// }
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
match item {
StringOrBinary::String(s) => {
dst.reserve(s.len());
dst.put(s.as_bytes());
Ok(())
}
StringOrBinary::Binary(b) => {
dst.reserve(b.len());
dst.put(Bytes::from(b));
Ok(())
}
}
}
}
impl futures_codec::Decoder for MaybeTextCodec {
type Item = StringOrBinary;
type Error = ShellError;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
impl MaybeTextCodec {
pub fn decode(&mut self, src: &[u8]) -> Result<Option<StringOrBinary>, ShellError> {
if src.is_empty() {
return Ok(None);
}
@ -96,31 +119,8 @@ impl futures_codec::Decoder for MaybeTextCodec {
StringOrBinary::String(s)
};
src.clear();
// src.clear();
Ok(Some(result))
}
}
#[cfg(test)]
mod tests {
use super::{MaybeTextCodec, StringOrBinary};
use bytes::BytesMut;
use futures_codec::Decoder;
// TODO: Write some more tests
#[test]
fn should_consume_all_bytes_from_source_when_temporary_buffer_overflows() {
let mut maybe_text = MaybeTextCodec::new(None);
let mut bytes = BytesMut::from("0123456789");
let text = maybe_text.decode(&mut bytes);
assert_eq!(
Ok(Some(StringOrBinary::String("0123456789".to_string()))),
text
);
assert!(bytes.is_empty());
}
}

View File

@ -1,8 +1,7 @@
use crate::command_args::CommandArgs;
use crate::whole_stream_command::{whole_stream_command, WholeStreamCommand};
use async_trait::async_trait;
use derive_new::new;
use futures::StreamExt;
use log::trace;
use nu_errors::ShellError;
use nu_plugin::jsonrpc::JsonRpc;
@ -94,7 +93,6 @@ pub struct PluginFilter {
config: Signature,
}
#[async_trait]
impl WholeStreamCommand for PluginFilter {
fn name(&self) -> &str {
&self.name
@ -108,22 +106,20 @@ impl WholeStreamCommand for PluginFilter {
&self.config.usage
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_filter(self.path.clone(), args).await
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_filter(self.path.clone(), args)
}
}
async fn run_filter(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
fn run_filter(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
trace!("filter_plugin :: {}", path);
let bos = futures::stream::iter(vec![
UntaggedValue::Primitive(Primitive::BeginningOfStream).into_untagged_value()
]);
let eos = futures::stream::iter(vec![
UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value()
]);
let bos = vec![UntaggedValue::Primitive(Primitive::BeginningOfStream).into_untagged_value()]
.into_iter();
let eos =
vec![UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value()].into_iter();
let args = args.evaluate_once().await?;
let args = args.evaluate_once()?;
let real_path = Path::new(&path);
let ext = real_path.extension();
@ -205,9 +201,10 @@ async fn run_filter(path: String, args: CommandArgs) -> Result<OutputStream, She
match response {
Ok(NuResult::response { params }) => match params {
Ok(params) => futures::stream::iter(params).to_output_stream(),
Err(e) => futures::stream::iter(vec![ReturnValue::Err(e)])
.to_output_stream(),
Ok(params) => params.into_iter().to_output_stream(),
Err(e) => {
vec![ReturnValue::Err(e)].into_iter().to_output_stream()
}
},
Err(e) => OutputStream::one(Err(
@ -265,25 +262,25 @@ async fn run_filter(path: String, args: CommandArgs) -> Result<OutputStream, She
match response {
Ok(NuResult::response { params }) => match params {
Ok(params) => futures::stream::iter(params).to_output_stream(),
Err(e) => futures::stream::iter(vec![ReturnValue::Err(e)])
.to_output_stream(),
Ok(params) => params.into_iter().to_output_stream(),
Err(e) => {
vec![ReturnValue::Err(e)].into_iter().to_output_stream()
}
},
Err(e) => futures::stream::iter(vec![Err(
ShellError::untagged_runtime_error(format!(
"Error while processing end_filter response: {:?} {}",
e, input
)),
)])
Err(e) => vec![Err(ShellError::untagged_runtime_error(format!(
"Error while processing end_filter response: {:?} {}",
e, input
)))]
.into_iter()
.to_output_stream(),
}
}
Err(e) => {
futures::stream::iter(vec![Err(ShellError::untagged_runtime_error(
format!("Error while reading end_filter response: {:?}", e),
))])
.to_output_stream()
}
Err(e) => vec![Err(ShellError::untagged_runtime_error(format!(
"Error while reading end_filter response: {:?}",
e
)))]
.into_iter()
.to_output_stream(),
};
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
@ -339,9 +336,10 @@ async fn run_filter(path: String, args: CommandArgs) -> Result<OutputStream, She
match response {
Ok(NuResult::response { params }) => match params {
Ok(params) => futures::stream::iter(params).to_output_stream(),
Err(e) => futures::stream::iter(vec![ReturnValue::Err(e)])
.to_output_stream(),
Ok(params) => params.into_iter().to_output_stream(),
Err(e) => {
vec![ReturnValue::Err(e)].into_iter().to_output_stream()
}
},
Err(e) => OutputStream::one(Err(
ShellError::untagged_runtime_error(format!(
@ -369,7 +367,6 @@ pub struct PluginSink {
config: Signature,
}
#[async_trait]
impl WholeStreamCommand for PluginSink {
fn name(&self) -> &str {
&self.name
@ -383,18 +380,18 @@ impl WholeStreamCommand for PluginSink {
&self.config.usage
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_sink(self.path.clone(), args).await
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_sink(self.path.clone(), args)
}
}
async fn run_sink(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?;
fn run_sink(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once()?;
let call_info = args.call_info.clone();
let input: Vec<Value> = args.input.collect().await;
let input: Vec<Value> = args.input.into_vec();
let request = JsonRpc::new("sink", (call_info.clone(), input));
let request = JsonRpc::new("sink", (call_info, input));
let request_raw = serde_json::to_string(&request);
if let Ok(request_raw) = request_raw {
if let Ok(mut tmpfile) = tempfile::NamedTempFile::new() {

View File

@ -1,7 +1,5 @@
use crate::{maybe_print_errors, path::canonicalize, run_block};
use crate::{MaybeTextCodec, StringOrBinary};
use futures::StreamExt;
use futures_codec::FramedRead;
use crate::{BufCodecReader, MaybeTextCodec, StringOrBinary};
use nu_errors::ShellError;
use nu_protocol::hir::{
Call, ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments,
@ -13,9 +11,9 @@ use nu_stream::{InputStream, ToInputStream};
use crate::EvaluationContext;
use log::{debug, trace};
use nu_source::{Span, Tag, Text};
use std::iter::Iterator;
use std::path::Path;
use std::{error::Error, sync::atomic::Ordering};
use std::{io::BufReader, iter::Iterator};
#[derive(Debug)]
pub enum LineResult {
@ -35,7 +33,7 @@ fn chomp_newline(s: &str) -> &str {
}
}
pub async fn run_script_in_dir(
pub fn run_script_in_dir(
script: String,
dir: &Path,
ctx: &EvaluationContext,
@ -45,14 +43,14 @@ pub async fn run_script_in_dir(
ctx.shell_manager
.set_path(dir.to_string_lossy().to_string());
run_script_standalone(script, false, ctx, false).await?;
run_script_standalone(script, false, ctx, false)?;
ctx.shell_manager.set_path(path_before);
Ok(())
}
/// Process the line by parsing the text to turn it into commands, classify those commands so that we understand what is being called in the pipeline, and then run this pipeline
pub async fn process_script(
pub fn process_script(
script_text: &str,
ctx: &EvaluationContext,
redirect_stdin: bool,
@ -161,8 +159,10 @@ pub async fn process_script(
}
let input_stream = if redirect_stdin {
let file = futures::io::AllowStdIo::new(std::io::stdin());
let stream = FramedRead::new(file, MaybeTextCodec::default()).map(|line| {
let file = std::io::stdin();
let buf_reader = BufReader::new(file);
let buf_codec = BufCodecReader::new(buf_reader, MaybeTextCodec::default());
let stream = buf_codec.map(|line| {
if let Ok(line) = line {
let primitive = match line {
StringOrBinary::String(s) => Primitive::String(s),
@ -184,47 +184,43 @@ pub async fn process_script(
trace!("{:#?}", block);
let result = run_block(&block, ctx, input_stream).await;
let result = run_block(&block, ctx, input_stream);
match result {
Ok(input) => {
// Running a pipeline gives us back a stream that we can then
// work through. At the top level, we just want to pull on the
// values to compute them.
use futures::stream::TryStreamExt;
let autoview_cmd = ctx
.get_command("autoview")
.expect("Could not find autoview command");
if let Ok(mut output_stream) = ctx
.run_command(
autoview_cmd,
Tag::unknown(),
Call::new(
Box::new(SpannedExpression::new(
Expression::string("autoview".to_string()),
Span::unknown(),
)),
if let Ok(mut output_stream) = ctx.run_command(
autoview_cmd,
Tag::unknown(),
Call::new(
Box::new(SpannedExpression::new(
Expression::string("autoview".to_string()),
Span::unknown(),
),
input,
)
.await
{
)),
Span::unknown(),
),
input,
) {
loop {
match output_stream.try_next().await {
Ok(Some(ReturnSuccess::Value(Value {
match output_stream.next() {
Some(Ok(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(e),
..
}))) => return LineResult::Error(line.to_string(), e),
Ok(Some(_item)) => {
Some(Ok(_item)) => {
if ctx.ctrl_c.load(Ordering::SeqCst) {
break;
}
}
Ok(None) => break,
Err(e) => return LineResult::Error(line.to_string(), e),
None => break,
Some(Err(e)) => return LineResult::Error(line.to_string(), e),
}
}
}
@ -236,7 +232,7 @@ pub async fn process_script(
}
}
pub async fn run_script_standalone(
pub fn run_script_standalone(
script_text: String,
redirect_stdin: bool,
context: &EvaluationContext,
@ -246,7 +242,7 @@ pub async fn run_script_standalone(
.shell_manager
.enter_script_mode()
.map_err(Box::new)?;
let line = process_script(&script_text, context, redirect_stdin, 0, false).await;
let line = process_script(&script_text, context, redirect_stdin, 0, false);
match line {
LineResult::Success(line) => {

View File

@ -4,7 +4,6 @@ use crate::command_args::EvaluatedWholeStreamCommandArgs;
use crate::maybe_text_codec::StringOrBinary;
pub use crate::shell::shell_args::{CdArgs, CopyArgs, LsArgs, MkdirArgs, MvArgs, RemoveArgs};
use encoding_rs::Encoding;
use futures::stream::BoxStream;
use nu_errors::ShellError;
use nu_source::{Span, Tag};
use std::path::{Path, PathBuf};
@ -41,7 +40,10 @@ pub trait Shell: std::fmt::Debug {
path: &Path,
name: Span,
with_encoding: Option<&'static Encoding>,
) -> Result<BoxStream<'static, Result<StringOrBinary, ShellError>>, ShellError>;
) -> Result<
Box<dyn Iterator<Item = Result<StringOrBinary, ShellError>> + Send + Sync>,
ShellError,
>;
fn save(
&mut self,
path: &Path,

View File

@ -1,7 +1,6 @@
use crate::shell::Shell;
use crate::{command_args::EvaluatedWholeStreamCommandArgs, FilesystemShell};
use crate::{filesystem::filesystem_shell::FilesystemShellMode, maybe_text_codec::StringOrBinary};
use futures::Stream;
use nu_stream::OutputStream;
use crate::shell::shell_args::{CdArgs, CopyArgs, LsArgs, MkdirArgs, MvArgs, RemoveArgs};
@ -85,8 +84,10 @@ impl ShellManager {
full_path: &Path,
name: Span,
with_encoding: Option<&'static Encoding>,
) -> Result<impl Stream<Item = Result<StringOrBinary, ShellError>> + Send + 'static, ShellError>
{
) -> Result<
Box<dyn Iterator<Item = Result<StringOrBinary, ShellError>> + Send + Sync>,
ShellError,
> {
self.shells.lock()[self.current_shell()].open(full_path, name, with_encoding)
}

View File

@ -3,7 +3,6 @@ use crate::maybe_text_codec::StringOrBinary;
use crate::shell::shell_args::{CdArgs, CopyArgs, LsArgs, MkdirArgs, MvArgs, RemoveArgs};
use crate::shell::Shell;
use encoding_rs::Encoding;
use futures::stream::BoxStream;
use nu_errors::ShellError;
use nu_protocol::ValueStructure;
use nu_protocol::{ReturnSuccess, ShellTypeName, UntaggedValue, Value};
@ -238,7 +237,10 @@ impl Shell for ValueShell {
_path: &Path,
_name: Span,
_with_encoding: Option<&'static Encoding>,
) -> Result<BoxStream<'static, Result<StringOrBinary, ShellError>>, ShellError> {
) -> Result<
Box<dyn Iterator<Item = Result<StringOrBinary, ShellError>> + Send + Sync>,
ShellError,
> {
Err(ShellError::unimplemented(
"open on help shell is not supported",
))

View File

@ -3,7 +3,6 @@ use crate::documentation::get_full_help;
use crate::evaluate::block::run_block;
use crate::evaluation_context::EvaluationContext;
use crate::example::Example;
use async_trait::async_trait;
use nu_errors::ShellError;
use nu_parser::ParserScope;
use nu_protocol::hir::Block;
@ -12,7 +11,6 @@ use nu_source::{DbgDocBldr, DebugDocBuilder, PrettyDebugWithSource, Span, Tag};
use nu_stream::{OutputStream, ToOutputStream};
use std::sync::Arc;
#[async_trait]
pub trait WholeStreamCommand: Send + Sync {
fn name(&self) -> &str;
@ -26,7 +24,7 @@ pub trait WholeStreamCommand: Send + Sync {
""
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError>;
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError>;
fn is_binary(&self) -> bool {
false
@ -45,7 +43,7 @@ pub trait WholeStreamCommand: Send + Sync {
// Custom commands are blocks, so we can use the information in the block to also
// implement a WholeStreamCommand
#[allow(clippy::suspicious_else_formatting)]
#[async_trait]
impl WholeStreamCommand for Block {
fn name(&self) -> &str {
&self.params.name
@ -59,14 +57,14 @@ impl WholeStreamCommand for Block {
&self.params.usage
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
let call_info = args.call_info.clone();
let mut block = self.clone();
block.set_redirect(call_info.args.external_redirection);
let ctx = EvaluationContext::from_args(&args);
let evaluated = call_info.evaluate(&ctx).await?;
let evaluated = call_info.evaluate(&ctx)?;
let input = args.input;
ctx.scope.enter_scope();
@ -153,7 +151,7 @@ impl WholeStreamCommand for Block {
}
}
}
let result = run_block(&block, &ctx, input).await;
let result = run_block(&block, &ctx, input);
ctx.scope.exit_scope();
result.map(|x| x.to_output_stream())
}
@ -210,14 +208,14 @@ impl Command {
self.0.examples()
}
pub async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
pub fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
if args.call_info.switch_present("help") {
let cl = self.0.clone();
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
UntaggedValue::string(get_full_help(&*cl, &args.scope)).into_value(Tag::unknown()),
))))
} else {
self.0.run(args).await
self.0.run(args)
}
}