Split nu-cli into nu-cli/nu-engine (#2898)

We split off the evaluation engine part of nu-cli into its own crate. This helps improve build times for nu-cli by 17% in my tests. It also helps us see a bit better what's the core engine portion vs the part specific to the interactive CLI piece.

There's more than can be done here, but I think it's a good start in the right direction.
This commit is contained in:
Jonathan Turner
2021-01-10 15:50:49 +13:00
committed by GitHub
parent 9de2144fc4
commit 93e8f6c05e
280 changed files with 1890 additions and 1750 deletions

View File

@ -12,6 +12,7 @@ doctest = false
[dependencies]
nu-data = {version = "0.25.1", path = "../nu-data"}
nu-engine = {version = "0.25.1", path = "../nu-engine"}
nu-errors = {version = "0.25.1", path = "../nu-errors"}
nu-json = {version = "0.25.1", path = "../nu-json"}
nu-parser = {version = "0.25.1", path = "../nu-parser"}

View File

@ -1,7 +1,13 @@
use crate::commands::classified::block::run_block;
use crate::commands::default_context::create_default_context;
use crate::evaluation_context::EvaluationContext;
use crate::env::basic_host::BasicHost;
use crate::line_editor::configure_ctrl_c;
use nu_engine::run_block;
use nu_engine::EvaluationContext;
use nu_engine::{FilesystemShell, Scope, ShellManager};
use parking_lot::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
#[allow(unused_imports)]
pub(crate) use crate::script::{process_script, LineResult};
@ -64,6 +70,40 @@ pub fn search_paths() -> Vec<std::path::PathBuf> {
search_paths
}
pub fn maybe_print_errors(context: &EvaluationContext, source: Text) -> bool {
let errors = context.current_errors.clone();
let mut errors = errors.lock();
if errors.len() > 0 {
let error = errors[0].clone();
*errors = vec![];
crate::script::print_err(error, &source);
true
} else {
false
}
}
pub fn basic_shell_manager() -> Result<ShellManager, Box<dyn Error>> {
Ok(ShellManager {
current_shell: Arc::new(AtomicUsize::new(0)),
shells: Arc::new(Mutex::new(vec![Box::new(FilesystemShell::basic()?)])),
})
}
pub fn basic_evaluation_context() -> Result<EvaluationContext, Box<dyn Error>> {
Ok(EvaluationContext {
scope: Scope::new(),
host: Arc::new(parking_lot::Mutex::new(Box::new(BasicHost))),
current_errors: Arc::new(Mutex::new(vec![])),
ctrl_c: Arc::new(AtomicBool::new(false)),
user_recently_used_autoenv_untrust: Arc::new(AtomicBool::new(false)),
shell_manager: crate::cli::basic_shell_manager()?,
windows_drives_previous_cwd: Arc::new(Mutex::new(std::collections::HashMap::new())),
})
}
pub async fn run_script_file(
file_contents: String,
redirect_stdin: bool,
@ -121,7 +161,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
// Give ourselves a scope to work in
context.scope.enter_scope();
let history_path = crate::commands::history::history_path(&configuration);
let history_path = nu_engine::history_path(&configuration);
let _ = rl.load_history(&history_path);
let mut session_text = String::new();
@ -182,7 +222,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
Ok(result) => match result.collect_string(Tag::unknown()).await {
Ok(string_result) => {
let errors = context.get_errors();
context.maybe_print_errors(Text::from(prompt_line));
maybe_print_errors(&context, Text::from(prompt_line));
context.clear_errors();
if !errors.is_empty() {
@ -277,7 +317,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
LineResult::Success(line) => {
rl.add_history_entry(&line);
let _ = rl.save_history(&history_path);
context.maybe_print_errors(Text::from(session_text.clone()));
maybe_print_errors(&context, Text::from(session_text.clone()));
}
LineResult::ClearHistory => {
@ -293,7 +333,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
print_err(err, &Text::from(session_text.clone()));
});
context.maybe_print_errors(Text::from(session_text.clone()));
maybe_print_errors(&context, Text::from(session_text.clone()));
}
LineResult::CtrlC => {
@ -337,7 +377,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
}
pub fn register_plugins(context: &mut EvaluationContext) -> Result<(), ShellError> {
if let Ok(plugins) = crate::plugin::scan(search_paths()) {
if let Ok(plugins) = nu_engine::plugin::build_plugin::scan(search_paths()) {
context.add_commands(
plugins
.into_iter()
@ -411,7 +451,7 @@ mod tests {
let (tokens, err) = nu_parser::lex(&data, 0);
let (lite_block, err2) = nu_parser::block(tokens);
if err.is_none() && err2.is_none() {
let context = crate::evaluation_context::EvaluationContext::basic().unwrap();
let context = crate::cli::basic_evaluation_context().unwrap();
let _ = nu_parser::classify_block(&lite_block, &context.scope);
}
true

View File

@ -136,9 +136,6 @@ pub(crate) mod wrap;
pub(crate) use autoview::Autoview;
pub(crate) use cd::Cd;
pub(crate) use command::{
whole_stream_command, Command, Example, UnevaluatedCallInfo, WholeStreamCommand,
};
pub(crate) use ansi::Ansi;
pub(crate) use append::Command as Append;
@ -290,8 +287,8 @@ pub(crate) use wrap::Wrap;
#[cfg(test)]
mod tests {
use super::*;
use crate::commands::whole_stream_command;
use crate::examples::{test_anchors, test_examples};
use nu_engine::{whole_stream_command, Command};
use nu_errors::ShellError;
fn full_tests() -> Vec<Command> {

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use ansi_term::Color;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
use serde::Deserialize;
@ -63,8 +63,7 @@ The file can contain several optional sections:
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&Autoenv, &args.scope))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Autoenv, &args.scope)).into_value(Tag::unknown()),
)))
}

View File

@ -1,6 +1,6 @@
use super::autoenv::read_trusted;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::SyntaxShape;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};

View File

@ -1,6 +1,6 @@
use super::autoenv::Trusted;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::SyntaxShape;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};

View File

@ -1,8 +1,8 @@
use crate::commands::autoview::options::{ConfigExtensions, NuConfig as AutoViewConfiguration};
use crate::commands::{UnevaluatedCallInfo, WholeStreamCommand};
use crate::prelude::*;
use crate::primitive::get_color_config;
use nu_data::value::format_leaf;
use nu_engine::{UnevaluatedCallInfo, WholeStreamCommand};
use nu_errors::ShellError;
use nu_protocol::hir::{self, Expression, ExternalRedirection, Literal, SpannedExpression};
use nu_protocol::{Primitive, Signature, UntaggedValue, Value};

View File

@ -1,8 +1,8 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
#[cfg(feature = "rich-benchmark")]
use heim::cpu::time;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::{Block, CapturedBlock, ClassifiedCommand, Group, InternalCommand, Pipeline},

View File

@ -1,8 +1,8 @@
use crate::prelude::*;
use nu_errors::ShellError;
use crate::commands::WholeStreamCommand;
use nu_data::value::format_leaf;
use nu_engine::WholeStreamCommand;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
#[derive(Deserialize)]

View File

@ -1,7 +1,7 @@
use crate::commands::{command::EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
use crate::prelude::*;
use chrono::{Datelike, Local, NaiveDate};
use indexmap::IndexMap;
use nu_engine::{EvaluatedWholeStreamCommandArgs, WholeStreamCommand};
use nu_errors::ShellError;
use nu_protocol::{Dictionary, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,16 +1,9 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use std::path::PathBuf;
use nu_engine::shell::CdArgs;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;
#[derive(Deserialize)]
pub struct CdArgs {
pub(crate) path: Option<Tagged<PathBuf>>,
}
pub struct Cd;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -28,8 +28,7 @@ impl WholeStreamCommand for Chart {
}
Ok(OutputStream::one(Ok(ReturnSuccess::Value(
UntaggedValue::string(crate::commands::help::get_help(&Chart, &args.scope))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Chart, &args.scope)).into_value(Tag::unknown()),
))))
}
}

View File

@ -1,214 +0,0 @@
use crate::commands::classified::expr::run_expression_block;
use crate::commands::classified::internal::run_internal_command;
use crate::evaluation_context::EvaluationContext;
use crate::prelude::*;
use async_recursion::async_recursion;
use futures::stream::TryStreamExt;
use nu_errors::ShellError;
use nu_protocol::hir::{
Block, Call, ClassifiedCommand, Expression, Pipeline, SpannedExpression, Synthetic,
};
use nu_protocol::{ReturnSuccess, UntaggedValue, Value};
use nu_stream::InputStream;
use std::sync::atomic::Ordering;
#[async_recursion]
pub async fn run_block(
block: &Block,
ctx: &EvaluationContext,
mut input: InputStream,
) -> Result<InputStream, ShellError> {
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
for (_, definition) in block.definitions.iter() {
ctx.scope.add_definition(definition.clone());
}
for group in &block.block {
match output {
Ok(inp) if inp.is_empty() => {}
Ok(inp) => {
// 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(),
)),
Span::unknown(),
),
inp,
)
.await
{
Ok(x) => x,
Err(e) => {
return Err(e);
}
};
match output_stream.try_next().await {
Ok(Some(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(e),
..
}))) => {
return Err(e);
}
Ok(Some(_item)) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
if ctx.ctrl_c.load(Ordering::SeqCst) {
return Ok(InputStream::empty());
}
}
Ok(None) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
}
Err(e) => {
return Err(e);
}
}
}
}
Err(e) => {
return Err(e);
}
}
output = Ok(InputStream::empty());
for pipeline in &group.pipelines {
match output {
Ok(inp) if inp.is_empty() => {}
Ok(inp) => {
let mut output_stream = inp.to_output_stream();
match output_stream.try_next().await {
Ok(Some(ReturnSuccess::Value(Value {
value: UntaggedValue::Error(e),
..
}))) => {
return Err(e);
}
Ok(Some(_item)) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
if ctx.ctrl_c.load(Ordering::SeqCst) {
// This early return doesn't return the result
// we have so far, but breaking out of this loop
// causes lifetime issues. A future contribution
// could attempt to return the current output.
// https://github.com/nushell/nushell/pull/2830#discussion_r550319687
return Ok(InputStream::empty());
}
}
Ok(None) => {
if let Some(err) = ctx.get_errors().get(0) {
ctx.clear_errors();
return Err(err.clone());
}
}
Err(e) => {
return Err(e);
}
}
}
Err(e) => {
return Err(e);
}
}
output = run_pipeline(pipeline, ctx, input).await;
input = InputStream::empty();
}
}
output
}
#[async_recursion]
async fn run_pipeline(
commands: &Pipeline,
ctx: &EvaluationContext,
mut input: InputStream,
) -> Result<InputStream, ShellError> {
for item in commands.list.clone() {
input = match item {
ClassifiedCommand::Dynamic(call) => {
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;
args.push(result);
}
}
match &call.head.expr {
Expression::Block(block) => {
ctx.scope.enter_scope();
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;
ctx.scope.exit_scope();
let result = result?;
return Ok(result);
}
Expression::Variable(v, span) => {
if let Some(value) = ctx.scope.get_var(v) {
match &value.value {
UntaggedValue::Block(captured_block) => {
ctx.scope.enter_scope();
ctx.scope.add_vars(&captured_block.captured.entries);
for (param, value) in captured_block
.block
.params
.positional
.iter()
.zip(args.iter())
{
ctx.scope.add_var(param.0.name(), value[0].clone());
}
let result = run_block(&captured_block.block, ctx, input).await;
ctx.scope.exit_scope();
let result = result?;
return Ok(result);
}
_ => {
return Err(ShellError::labeled_error("Dynamic commands must start with a block (or variable pointing to a block)", "needs to be a block", call.head.span));
}
}
} else {
return Err(ShellError::labeled_error(
"Variable not found",
"variable not found",
span,
));
}
}
_ => {
return Err(ShellError::labeled_error("Dynamic commands must start with a block (or variable pointing to a block)", "needs to be a block", call.head.span));
}
}
}
ClassifiedCommand::Expr(expr) => run_expression_block(&*expr, ctx).await?,
ClassifiedCommand::Error(err) => return Err(err.into()),
ClassifiedCommand::Internal(left) => run_internal_command(left, ctx, input).await?,
};
}
Ok(input)
}

View File

@ -1,22 +0,0 @@
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*;
use log::{log_enabled, trace};
use futures::stream::once;
use nu_errors::ShellError;
use nu_protocol::hir::SpannedExpression;
pub(crate) async fn run_expression_block(
expr: &SpannedExpression,
ctx: &EvaluationContext,
) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::expr", "->");
trace!(target: "nu::run::expr", "{:?}", expr);
}
let output = evaluate_baseline_expr(expr, ctx).await?;
Ok(once(async { Ok(output) }).to_input_stream())
}

View File

@ -1,7 +1,7 @@
use crate::commands::classified::maybe_text_codec::{MaybeTextCodec, StringOrBinary};
use crate::evaluate::evaluate_baseline_expr;
use crate::futures::ThreadedReceiver;
use crate::prelude::*;
use nu_engine::evaluate_baseline_expr;
use nu_engine::{MaybeTextCodec, StringOrBinary};
use std::borrow::Cow;
use std::io::Write;
@ -18,6 +18,7 @@ use nu_protocol::hir::Expression;
use nu_protocol::hir::{ExternalCommand, ExternalRedirection};
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
use nu_source::Tag;
use nu_stream::trace_stream;
pub(crate) async fn run_external_command(
command: ExternalCommand,
@ -532,7 +533,7 @@ mod tests {
add_double_quotes, argument_is_quoted, escape_double_quotes, expand_tilde, remove_quotes,
};
#[cfg(feature = "which")]
use super::{run_external_command, EvaluationContext, InputStream};
use super::{run_external_command, InputStream};
#[cfg(feature = "which")]
use futures::executor::block_on;
@ -560,8 +561,8 @@ mod tests {
let cmd = ExternalBuilder::for_name("i_dont_exist.exe").build();
let input = InputStream::empty();
let mut ctx =
EvaluationContext::basic().expect("There was a problem creating a basic context.");
let mut ctx = crate::cli::basic_evaluation_context()
.expect("There was a problem creating a basic context.");
assert!(
run_external_command(cmd, &mut ctx, input, ExternalRedirection::Stdout)
@ -575,7 +576,7 @@ mod tests {
// async fn failure_run() -> Result<(), ShellError> {
// let cmd = ExternalBuilder::for_name("fail").build();
// let mut ctx = EvaluationContext::basic().expect("There was a problem creating a basic context.");
// let mut ctx = crate::cli::basic_evaluation_context().expect("There was a problem creating a basic context.");
// let stream = run_external_command(cmd, &mut ctx, None, false)
// .await?
// .expect("There was a problem running the external command.");

View File

@ -1,250 +0,0 @@
use std::sync::atomic::Ordering;
use crate::commands::UnevaluatedCallInfo;
use crate::prelude::*;
use log::{log_enabled, trace};
use nu_errors::ShellError;
use nu_protocol::hir::{ExternalRedirection, InternalCommand};
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
pub(crate) async fn run_internal_command(
command: InternalCommand,
context: &EvaluationContext,
input: InputStream,
) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::internal", "->");
trace!(target: "nu::run::internal", "{}", command.name);
}
let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", "input" = input);
let internal_command = context.scope.expect_command(&command.name);
if command.name == "autoenv untrust" {
context
.user_recently_used_autoenv_untrust
.store(true, Ordering::SeqCst);
}
let result = {
context
.run_command(
internal_command?,
Tag::unknown_anchor(command.name_span),
command.args.clone(),
objects,
)
.await?
};
let head = Arc::new(command.args.head.clone());
let context = context.clone();
let command = Arc::new(command);
Ok(InputStream::from_stream(
result
.then(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 => std::process::exit(0), // 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(),
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),
},
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::EnterHelpShell(value) => match value {
Value {
value: UntaggedValue::Primitive(Primitive::String(cmd)),
tag,
} => {
context.shell_manager.insert_at_current(Box::new(
match HelpShell::for_command(
UntaggedValue::string(cmd).into_value(tag),
&context.scope,
) {
Ok(v) => v,
Err(err) => {
context.error(err);
return InputStream::empty();
}
},
));
InputStream::from_stream(futures::stream::iter(vec![]))
}
_ => {
context.shell_manager.insert_at_current(Box::new(
match HelpShell::index(&context.scope) {
Ok(v) => v,
Err(err) => {
context.error(err);
return InputStream::empty();
}
},
));
InputStream::from_stream(futures::stream::iter(vec![]))
}
},
CommandAction::EnterValueShell(value) => {
context
.shell_manager
.insert_at_current(Box::new(ValueShell::new(value)));
InputStream::from_stream(futures::stream::iter(vec![]))
}
CommandAction::EnterShell(location) => {
context.shell_manager.insert_at_current(Box::new(
match FilesystemShell::with_location(location) {
Ok(v) => v,
Err(err) => {
context.error(err.into());
return InputStream::empty();
}
},
));
InputStream::from_stream(futures::stream::iter(vec![]))
}
CommandAction::AddPlugins(path) => {
match crate::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()
}
Err(reason) => {
context.error(reason);
InputStream::empty()
}
}
}
CommandAction::PreviousShell => {
context.shell_manager.prev();
InputStream::empty()
}
CommandAction::NextShell => {
context.shell_manager.next();
InputStream::empty()
}
CommandAction::LeaveShell => {
context.shell_manager.remove_at_current();
if context.shell_manager.is_empty() {
std::process::exit(0); // TODO: save history.txt
}
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())),
))
}

View File

@ -1,127 +0,0 @@
use bytes::{BufMut, Bytes, BytesMut};
use nu_errors::ShellError;
extern crate encoding_rs;
use encoding_rs::{CoderResult, Decoder, Encoding, UTF_8};
#[cfg(not(test))]
const OUTPUT_BUFFER_SIZE: usize = 8192;
#[cfg(test)]
const OUTPUT_BUFFER_SIZE: usize = 4;
#[derive(Debug, Eq, PartialEq)]
pub enum StringOrBinary {
String(String),
Binary(Vec<u8>),
}
pub struct MaybeTextCodec {
decoder: Decoder,
}
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 {
let decoder = match encoding {
Some(e) => e.new_decoder_with_bom_removal(),
None => UTF_8.new_decoder(),
};
MaybeTextCodec { decoder }
}
}
impl Default for MaybeTextCodec {
fn default() -> Self {
MaybeTextCodec {
decoder: UTF_8.new_decoder(),
}
}
}
impl futures_codec::Encoder for MaybeTextCodec {
type Item = StringOrBinary;
type Error = std::io::Error;
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> {
if src.is_empty() {
return Ok(None);
}
let mut s = String::with_capacity(OUTPUT_BUFFER_SIZE);
let (res, _read, replacements) = self.decoder.decode_to_string(src, &mut s, false);
let result = if replacements {
// If we had to make replacements when converting to utf8, fall back to binary
StringOrBinary::Binary(src.to_vec())
} else {
// If original buffer size is too small, we continue to allocate new Strings and append
// them to the result until the input buffer is smaller than the allocated String
if let CoderResult::OutputFull = res {
let mut buffer = String::with_capacity(OUTPUT_BUFFER_SIZE);
loop {
let (res, _read, _replacements) =
self.decoder
.decode_to_string(&src[s.len()..], &mut buffer, false);
s.push_str(&buffer);
if let CoderResult::InputEmpty = res {
break;
}
buffer.clear();
}
}
StringOrBinary::String(s)
};
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,10 +1,5 @@
pub(crate) mod block;
mod dynamic;
pub(crate) mod expr;
pub(crate) mod external;
pub(crate) mod internal;
pub(crate) mod maybe_text_codec;
pub(crate) mod plugin;
#[allow(unused_imports)]
pub(crate) use dynamic::Command as DynamicCommand;

View File

@ -1,447 +0,0 @@
use crate::commands::command::{whole_stream_command, WholeStreamCommand};
use crate::prelude::*;
use derive_new::new;
use log::trace;
use nu_errors::ShellError;
use nu_plugin::jsonrpc::JsonRpc;
use nu_protocol::{Primitive, ReturnValue, Signature, UntaggedValue, Value};
use serde::{self, Deserialize, Serialize};
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Write;
use std::path::Path;
use std::process::{Child, Command, Stdio};
#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "method")]
#[allow(non_camel_case_types)]
pub enum NuResult {
response {
params: Result<VecDeque<ReturnValue>, ShellError>,
},
}
enum PluginCommand {
Filter(PluginFilter),
Sink(PluginSink),
}
impl PluginCommand {
fn command(self) -> Result<crate::commands::Command, ShellError> {
match self {
PluginCommand::Filter(cmd) => Ok(whole_stream_command(cmd)),
PluginCommand::Sink(cmd) => Ok(whole_stream_command(cmd)),
}
}
}
enum PluginMode {
Filter,
Sink,
}
pub struct PluginCommandBuilder {
mode: PluginMode,
name: String,
path: String,
config: Signature,
}
impl PluginCommandBuilder {
pub fn new(
name: impl Into<String>,
path: impl Into<String>,
config: impl Into<Signature>,
) -> Self {
let config = config.into();
PluginCommandBuilder {
mode: if config.is_filter {
PluginMode::Filter
} else {
PluginMode::Sink
},
name: name.into(),
path: path.into(),
config,
}
}
pub fn build(&self) -> Result<crate::commands::Command, ShellError> {
let mode = &self.mode;
let name = self.name.clone();
let path = self.path.clone();
let config = self.config.clone();
let cmd = match mode {
PluginMode::Filter => PluginCommand::Filter(PluginFilter { name, path, config }),
PluginMode::Sink => PluginCommand::Sink(PluginSink { name, path, config }),
};
cmd.command()
}
}
#[derive(new)]
pub struct PluginFilter {
name: String,
path: String,
config: Signature,
}
#[async_trait]
impl WholeStreamCommand for PluginFilter {
fn name(&self) -> &str {
&self.name
}
fn signature(&self) -> Signature {
self.config.clone()
}
fn usage(&self) -> &str {
&self.config.usage
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_filter(self.path.clone(), (args)).await
}
}
async 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 args = args.evaluate_once().await?;
let real_path = Path::new(&path);
let ext = real_path.extension();
let ps1_file = match ext {
Some(ext) => ext == "ps1",
None => false,
};
let mut child: Child = if ps1_file {
Command::new("pwsh")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.args(&[
"-NoLogo",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
&real_path.to_string_lossy(),
])
.spawn()
.expect("Failed to spawn PowerShell process")
} else {
Command::new(path)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Failed to spawn child process")
};
let call_info = args.call_info.clone();
trace!("filtering :: {:?}", call_info);
Ok(bos
.chain(args.input)
.chain(eos)
.map(move |item| {
match item {
Value {
value: UntaggedValue::Primitive(Primitive::BeginningOfStream),
..
} => {
// Beginning of the stream
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout);
let request = JsonRpc::new("begin_filter", call_info.clone());
let request_raw = serde_json::to_string(&request);
trace!("begin_filter:request {:?}", &request_raw);
match request_raw {
Err(_) => {
return OutputStream::one(Err(ShellError::labeled_error(
"Could not load json from plugin",
"could not load json from plugin",
&call_info.name_tag,
)));
}
Ok(request_raw) => {
match stdin.write(format!("{}\n", request_raw).as_bytes()) {
Ok(_) => {}
Err(err) => {
return OutputStream::one(Err(ShellError::unexpected(
format!("{}", err),
)));
}
}
}
}
let mut input = String::new();
match reader.read_line(&mut input) {
Ok(_) => {
let response = serde_json::from_str::<NuResult>(&input);
trace!("begin_filter:response {:?}", &response);
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(),
},
Err(e) => OutputStream::one(Err(
ShellError::untagged_runtime_error(format!(
"Error while processing begin_filter response: {:?} {}",
e, input
)),
)),
}
}
Err(e) => OutputStream::one(Err(ShellError::untagged_runtime_error(
format!("Error while reading begin_filter response: {:?}", e),
))),
}
}
Value {
value: UntaggedValue::Primitive(Primitive::EndOfStream),
..
} => {
// post stream contents
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout);
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("end_filter", vec![]);
let request_raw = serde_json::to_string(&request);
trace!("end_filter:request {:?}", &request_raw);
match request_raw {
Err(_) => {
return OutputStream::one(Err(ShellError::labeled_error(
"Could not load json from plugin",
"could not load json from plugin",
&call_info.name_tag,
)));
}
Ok(request_raw) => {
match stdin.write(format!("{}\n", request_raw).as_bytes()) {
Ok(_) => {}
Err(err) => {
return OutputStream::one(Err(ShellError::unexpected(
format!("{}", err),
)));
}
}
}
}
let mut input = String::new();
let stream = match reader.read_line(&mut input) {
Ok(_) => {
let response = serde_json::from_str::<NuResult>(&input);
trace!("end_filter:response {:?}", &response);
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(),
},
Err(e) => futures::stream::iter(vec![Err(
ShellError::untagged_runtime_error(format!(
"Error while processing end_filter response: {:?} {}",
e, input
)),
)])
.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()
}
};
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let request: JsonRpc<std::vec::Vec<Value>> = JsonRpc::new("quit", vec![]);
let request_raw = serde_json::to_string(&request);
trace!("quit:request {:?}", &request_raw);
match request_raw {
Ok(request_raw) => {
let _ = stdin.write(format!("{}\n", request_raw).as_bytes());
// TODO: Handle error
}
Err(e) => {
return OutputStream::one(Err(ShellError::untagged_runtime_error(
format!("Error while processing quit response: {:?}", e),
)));
}
}
let _ = child.wait();
stream
}
v => {
// Stream contents
let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout");
let mut reader = BufReader::new(stdout);
let request = JsonRpc::new("filter", v);
let request_raw = serde_json::to_string(&request);
trace!("filter:request {:?}", &request_raw);
match request_raw {
Ok(request_raw) => {
let _ = stdin.write(format!("{}\n", request_raw).as_bytes());
// TODO: Handle error
}
Err(e) => {
return OutputStream::one(Err(ShellError::untagged_runtime_error(
format!("Error while processing filter response: {:?}", e),
)));
}
}
let mut input = String::new();
match reader.read_line(&mut input) {
Ok(_) => {
let response = serde_json::from_str::<NuResult>(&input);
trace!("filter:response {:?}", &response);
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(),
},
Err(e) => OutputStream::one(Err(
ShellError::untagged_runtime_error(format!(
"Error while processing filter response: {:?}\n== input ==\n{}",
e, input
)),
)),
}
}
Err(e) => OutputStream::one(Err(ShellError::untagged_runtime_error(
format!("Error while reading filter response: {:?}", e),
))),
}
}
}
})
.flatten()
.to_output_stream())
}
#[derive(new)]
pub struct PluginSink {
name: String,
path: String,
config: Signature,
}
#[async_trait]
impl WholeStreamCommand for PluginSink {
fn name(&self) -> &str {
&self.name
}
fn signature(&self) -> Signature {
self.config.clone()
}
fn usage(&self) -> &str {
&self.config.usage
}
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
run_sink(self.path.clone(), args).await
}
}
async fn run_sink(path: String, args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?;
let call_info = args.call_info.clone();
let input: Vec<Value> = args.input.collect().await;
let request = JsonRpc::new("sink", (call_info.clone(), input));
let request_raw = serde_json::to_string(&request);
if let Ok(request_raw) = request_raw {
if let Ok(mut tmpfile) = tempfile::NamedTempFile::new() {
let _ = writeln!(tmpfile, "{}", request_raw);
let _ = tmpfile.flush();
let real_path = Path::new(&path);
let ext = real_path.extension();
let ps1_file = match ext {
Some(ext) => ext == "ps1",
None => false,
};
// TODO: This sink may not work in powershell, trying to find
// an example of what CallInfo would look like in this temp file
let child = if ps1_file {
Command::new("pwsh")
.args(&[
"-NoLogo",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
&real_path.to_string_lossy(),
&tmpfile
.path()
.to_str()
.expect("Failed getting tmpfile path"),
])
.spawn()
} else {
Command::new(path).arg(&tmpfile.path()).spawn()
};
if let Ok(mut child) = child {
let _ = child.wait();
Ok(OutputStream::empty())
} else {
Err(ShellError::untagged_runtime_error(
"Could not create process for sink command",
))
}
} else {
Err(ShellError::untagged_runtime_error(
"Could not open file to send sink command message",
))
}
} else {
Err(ShellError::untagged_runtime_error(
"Could not create message to sink command",
))
}
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::Signature;
use std::process::Command;

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::stream::StreamExt;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, Value};

View File

@ -1,111 +1,9 @@
use crate::deserializer::ConfigDeserializer;
use crate::evaluate::evaluate_args::evaluate_args;
use crate::prelude::*;
use crate::{commands::help::get_help, run_block};
use derive_new::new;
use getset::Getters;
use nu_engine::Command;
use nu_errors::ShellError;
use nu_protocol::hir::{self, Block};
use nu_protocol::{CallInfo, EvaluatedArgs, ReturnSuccess, Signature, UntaggedValue, Value};
use parking_lot::Mutex;
use serde::Deserialize;
use std::ops::Deref;
use std::sync::atomic::AtomicBool;
#[derive(Debug, Clone)]
pub struct UnevaluatedCallInfo {
pub args: hir::Call,
pub name_tag: Tag,
}
impl UnevaluatedCallInfo {
pub async fn evaluate(self, ctx: &EvaluationContext) -> Result<CallInfo, ShellError> {
let args = evaluate_args(&self.args, ctx).await?;
Ok(CallInfo {
args,
name_tag: self.name_tag,
})
}
pub fn switch_present(&self, switch: &str) -> bool {
self.args.switch_preset(switch)
}
}
#[derive(Getters)]
#[get = "pub(crate)"]
pub struct CommandArgs {
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub ctrl_c: Arc<AtomicBool>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub shell_manager: ShellManager,
pub call_info: UnevaluatedCallInfo,
pub scope: Scope,
pub input: InputStream,
}
#[derive(Getters, Clone)]
#[get = "pub(crate)"]
pub struct RawCommandArgs {
pub host: Arc<parking_lot::Mutex<Box<dyn Host>>>,
pub ctrl_c: Arc<AtomicBool>,
pub current_errors: Arc<Mutex<Vec<ShellError>>>,
pub shell_manager: ShellManager,
pub scope: Scope,
pub call_info: UnevaluatedCallInfo,
}
impl RawCommandArgs {
pub fn with_input(self, input: impl Into<InputStream>) -> CommandArgs {
CommandArgs {
host: self.host,
ctrl_c: self.ctrl_c,
current_errors: self.current_errors,
shell_manager: self.shell_manager,
call_info: self.call_info,
scope: self.scope,
input: input.into(),
}
}
}
impl std::fmt::Debug for CommandArgs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.call_info.fmt(f)
}
}
impl CommandArgs {
pub async 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 shell_manager = self.shell_manager.clone();
let input = self.input;
let call_info = self.call_info.evaluate(&ctx).await?;
let scope = self.scope.clone();
Ok(EvaluatedWholeStreamCommandArgs::new(
host,
ctrl_c,
shell_manager,
call_info,
input,
scope,
))
}
pub async fn process<'de, T: Deserialize<'de>>(self) -> Result<(T, InputStream), ShellError> {
let args = self.evaluate_once().await?;
let call_info = args.call_info.clone();
let mut deserializer = ConfigDeserializer::from_call_info(call_info);
Ok((T::deserialize(&mut deserializer)?, args.input))
}
}
pub struct RunnableContext {
pub input: InputStream,
pub shell_manager: ShellManager,
@ -121,275 +19,3 @@ impl RunnableContext {
self.scope.get_command(name)
}
}
pub struct EvaluatedWholeStreamCommandArgs {
pub args: EvaluatedCommandArgs,
pub input: InputStream,
}
impl Deref for EvaluatedWholeStreamCommandArgs {
type Target = EvaluatedCommandArgs;
fn deref(&self) -> &Self::Target {
&self.args
}
}
impl EvaluatedWholeStreamCommandArgs {
pub fn new(
host: Arc<parking_lot::Mutex<dyn Host>>,
ctrl_c: Arc<AtomicBool>,
shell_manager: ShellManager,
call_info: CallInfo,
input: impl Into<InputStream>,
scope: Scope,
) -> EvaluatedWholeStreamCommandArgs {
EvaluatedWholeStreamCommandArgs {
args: EvaluatedCommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
scope,
},
input: input.into(),
}
}
pub fn name_tag(&self) -> Tag {
self.args.call_info.name_tag.clone()
}
pub fn parts(self) -> (InputStream, EvaluatedArgs) {
let EvaluatedWholeStreamCommandArgs { args, input } = self;
(input, args.call_info.args)
}
pub fn split(self) -> (InputStream, EvaluatedCommandArgs) {
let EvaluatedWholeStreamCommandArgs { args, input } = self;
(input, args)
}
}
#[derive(Getters, new)]
#[get = "pub(crate)"]
pub struct EvaluatedCommandArgs {
pub host: Arc<parking_lot::Mutex<dyn Host>>,
pub ctrl_c: Arc<AtomicBool>,
pub shell_manager: ShellManager,
pub call_info: CallInfo,
pub scope: Scope,
}
impl EvaluatedCommandArgs {
pub fn nth(&self, pos: usize) -> Option<&Value> {
self.call_info.args.nth(pos)
}
/// Get the nth positional argument, error if not possible
pub fn expect_nth(&self, pos: usize) -> Result<&Value, ShellError> {
self.call_info
.args
.nth(pos)
.ok_or_else(|| ShellError::unimplemented("Better error: expect_nth"))
}
pub fn get(&self, name: &str) -> Option<&Value> {
self.call_info.args.get(name)
}
pub fn has(&self, name: &str) -> bool {
self.call_info.args.has(name)
}
}
pub struct Example {
pub example: &'static str,
pub description: &'static str,
pub result: Option<Vec<Value>>,
}
#[async_trait]
pub trait WholeStreamCommand: Send + Sync {
fn name(&self) -> &str;
fn signature(&self) -> Signature {
Signature::new(self.name()).desc(self.usage()).filter()
}
fn usage(&self) -> &str;
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError>;
fn is_binary(&self) -> bool {
false
}
// Commands that are not meant to be run by users
fn is_internal(&self) -> bool {
false
}
fn examples(&self) -> Vec<Example> {
Vec::new()
}
}
// 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
}
fn signature(&self) -> Signature {
self.params.clone()
}
fn usage(&self) -> &str {
&self.params.usage
}
async 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 input = args.input;
ctx.scope.enter_scope();
if let Some(args) = evaluated.args.positional {
// FIXME: do not do this
for arg in args.into_iter().zip(self.params.positional.iter()) {
let name = arg.1 .0.name();
if name.starts_with('$') {
ctx.scope.add_var(name, arg.0);
} else {
ctx.scope.add_var(format!("${}", name), arg.0);
}
}
}
if let Some(args) = evaluated.args.named {
for named in &block.params.named {
let name = named.0;
if let Some(value) = args.get(name) {
if name.starts_with('$') {
ctx.scope.add_var(name, value.clone());
} else {
ctx.scope.add_var(format!("${}", name), value.clone());
}
} else if name.starts_with('$') {
ctx.scope
.add_var(name, UntaggedValue::nothing().into_untagged_value());
} else {
ctx.scope.add_var(
format!("${}", name),
UntaggedValue::nothing().into_untagged_value(),
);
}
}
} else {
for named in &block.params.named {
let name = named.0;
if name.starts_with('$') {
ctx.scope
.add_var(name, UntaggedValue::nothing().into_untagged_value());
} else {
ctx.scope.add_var(
format!("${}", name),
UntaggedValue::nothing().into_untagged_value(),
);
}
}
}
let result = run_block(&block, &ctx, input).await;
ctx.scope.exit_scope();
result.map(|x| x.to_output_stream())
}
fn is_binary(&self) -> bool {
false
}
fn is_internal(&self) -> bool {
false
}
fn examples(&self) -> Vec<Example> {
vec![]
}
}
#[derive(Clone)]
pub struct Command(Arc<dyn WholeStreamCommand>);
impl PrettyDebugWithSource for Command {
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
b::typed(
"whole stream command",
b::description(self.name())
+ b::space()
+ b::equals()
+ b::space()
+ self.signature().pretty_debug(source),
)
}
}
impl std::fmt::Debug for Command {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Command({})", self.name())
}
}
impl Command {
pub fn name(&self) -> &str {
self.0.name()
}
pub fn signature(&self) -> Signature {
self.0.signature()
}
pub fn usage(&self) -> &str {
self.0.usage()
}
pub fn examples(&self) -> Vec<Example> {
self.0.examples()
}
pub async 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_help(&*cl, &args.scope)).into_value(Tag::unknown()),
))))
} else {
self.0.run(args).await
}
}
pub fn is_binary(&self) -> bool {
self.0.is_binary()
}
pub fn is_internal(&self) -> bool {
self.0.is_internal()
}
pub fn stream_command(&self) -> &dyn WholeStreamCommand {
&*self.0
}
}
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command {
Command(Arc::new(command))
}

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::future;
use futures::stream::StreamExt;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};

View File

@ -1,8 +1,9 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use crate::{CommandArgs, OutputStream};
use nu_engine::CommandArgs;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
use nu_stream::OutputStream;
pub struct Command;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ColumnPath, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::stream::StreamExt;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, UntaggedValue, Value};

View File

@ -1,19 +1,10 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;
use std::path::PathBuf;
pub struct Cpy;
#[derive(Deserialize)]
pub struct CopyArgs {
pub src: Tagged<PathBuf>,
pub dst: Tagged<PathBuf>,
pub recursive: Tagged<bool>,
}
#[async_trait]
impl WholeStreamCommand for Cpy {
fn name(&self) -> &str {

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -21,8 +21,7 @@ impl WholeStreamCommand for Command {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&Command, &args.scope))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Command, &args.scope)).into_value(Tag::unknown()),
)))
}
}

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
Dictionary, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use chrono_tz::TZ_VARIANTS;
use indexmap::IndexMap;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Dictionary, ReturnSuccess, Signature, UntaggedValue};

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use chrono::{DateTime, Local};
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, UntaggedValue};

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use chrono::{Datelike, Timelike};
use indexmap::IndexMap;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Dictionary, Primitive, ReturnSuccess, Signature, UntaggedValue, Value};

View File

@ -1,6 +1,6 @@
use crate::commands::date::parser::{datetime_in_timezone, ParseErrorKind};
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -3,7 +3,7 @@ use chrono::{DateTime, Utc};
use nu_errors::ShellError;
use crate::commands::date::utils::date_to_value;
use crate::commands::WholeStreamCommand;
use nu_engine::WholeStreamCommand;
use nu_protocol::Signature;
pub struct Date;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, Signature, SyntaxShape, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,8 +1,9 @@
use crate::prelude::*;
use nu_engine::whole_stream_command;
use std::error::Error;
pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Box<dyn Error>> {
let context = EvaluationContext::basic()?;
let context = crate::cli::basic_evaluation_context()?;
{
use crate::commands::*;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};

View File

@ -1,6 +1,6 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, hir::ExternalRedirection, Signature, SyntaxShape, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,13 +1,11 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use filesize::file_real_size_fast;
use glob::*;
use indexmap::map::IndexMap;
use nu_engine::WholeStreamCommand;
use nu_engine::{DirBuilder, DirInfo, FileInfo};
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape};
use nu_source::Tagged;
use std::path::PathBuf;
use std::sync::atomic::Ordering;
const NAME: &str = "du";
const GLOB_PARAMS: MatchOptions = MatchOptions {
@ -156,269 +154,11 @@ async fn du(args: CommandArgs) -> Result<OutputStream, ShellError> {
.to_output_stream())
}
pub struct DirBuilder {
tag: Tag,
min: Option<u64>,
deref: bool,
exclude: Option<Pattern>,
all: bool,
}
impl DirBuilder {
pub fn new(
tag: Tag,
min: Option<u64>,
deref: bool,
exclude: Option<Pattern>,
all: bool,
) -> DirBuilder {
DirBuilder {
tag,
min,
deref,
exclude,
all,
}
}
}
pub struct DirInfo {
dirs: Vec<DirInfo>,
files: Vec<FileInfo>,
errors: Vec<ShellError>,
size: u64,
blocks: u64,
path: PathBuf,
tag: Tag,
}
struct FileInfo {
path: PathBuf,
size: u64,
blocks: Option<u64>,
tag: Tag,
}
impl FileInfo {
fn new(path: impl Into<PathBuf>, deref: bool, tag: Tag) -> Result<Self, ShellError> {
let path = path.into();
let m = if deref {
std::fs::metadata(&path)
} else {
std::fs::symlink_metadata(&path)
};
match m {
Ok(d) => {
let block_size = file_real_size_fast(&path, &d).ok();
Ok(FileInfo {
path,
blocks: block_size,
size: d.len(),
tag,
})
}
Err(e) => Err(e.into()),
}
}
}
impl DirInfo {
pub fn new(
path: impl Into<PathBuf>,
params: &DirBuilder,
depth: Option<u64>,
ctrl_c: Arc<AtomicBool>,
) -> Self {
let path = path.into();
let mut s = Self {
dirs: Vec::new(),
errors: Vec::new(),
files: Vec::new(),
size: 0,
blocks: 0,
tag: params.tag.clone(),
path,
};
match std::fs::read_dir(&s.path) {
Ok(d) => {
for f in d {
if ctrl_c.load(Ordering::SeqCst) {
break;
}
match f {
Ok(i) => match i.file_type() {
Ok(t) if t.is_dir() => {
s = s.add_dir(i.path(), depth, &params, ctrl_c.clone())
}
Ok(_t) => s = s.add_file(i.path(), &params),
Err(e) => s = s.add_error(e.into()),
},
Err(e) => s = s.add_error(e.into()),
}
}
}
Err(e) => s = s.add_error(e.into()),
}
s
}
fn add_dir(
mut self,
path: impl Into<PathBuf>,
mut depth: Option<u64>,
params: &DirBuilder,
ctrl_c: Arc<AtomicBool>,
) -> Self {
if let Some(current) = depth {
if let Some(new) = current.checked_sub(1) {
depth = Some(new);
} else {
return self;
}
}
let d = DirInfo::new(path, &params, depth, ctrl_c);
self.size += d.size;
self.blocks += d.blocks;
self.dirs.push(d);
self
}
fn add_file(mut self, f: impl Into<PathBuf>, params: &DirBuilder) -> Self {
let f = f.into();
let include = params
.exclude
.as_ref()
.map_or(true, |x| !x.matches_path(&f));
if include {
match FileInfo::new(f, params.deref, self.tag.clone()) {
Ok(file) => {
let inc = params.min.map_or(true, |s| file.size >= s);
if inc {
self.size += file.size;
self.blocks += file.blocks.unwrap_or(0);
if params.all {
self.files.push(file);
}
}
}
Err(e) => self = self.add_error(e),
}
}
self
}
fn add_error(mut self, e: ShellError) -> Self {
self.errors.push(e);
self
}
pub fn get_size(&self) -> u64 {
self.size
}
}
fn glob_err_into(e: GlobError) -> ShellError {
let e = e.into_error();
ShellError::from(e)
}
fn value_from_vec<V>(vec: Vec<V>, tag: &Tag) -> Value
where
V: Into<Value>,
{
if vec.is_empty() {
UntaggedValue::nothing()
} else {
let values = vec.into_iter().map(Into::into).collect::<Vec<Value>>();
UntaggedValue::Table(values)
}
.into_value(tag)
}
impl From<DirInfo> for Value {
fn from(d: DirInfo) -> Self {
let mut r: IndexMap<String, Value> = IndexMap::new();
r.insert(
"path".to_string(),
UntaggedValue::filepath(d.path).into_value(&d.tag),
);
r.insert(
"apparent".to_string(),
UntaggedValue::filesize(d.size).into_value(&d.tag),
);
r.insert(
"physical".to_string(),
UntaggedValue::filesize(d.blocks).into_value(&d.tag),
);
r.insert("directories".to_string(), value_from_vec(d.dirs, &d.tag));
r.insert("files".to_string(), value_from_vec(d.files, &d.tag));
if !d.errors.is_empty() {
let v = UntaggedValue::Table(
d.errors
.into_iter()
.map(move |e| UntaggedValue::Error(e).into_untagged_value())
.collect::<Vec<Value>>(),
)
.into_value(&d.tag);
r.insert("errors".to_string(), v);
}
Value {
value: UntaggedValue::row(r),
tag: d.tag,
}
}
}
impl From<FileInfo> for Value {
fn from(f: FileInfo) -> Self {
let mut r: IndexMap<String, Value> = IndexMap::new();
r.insert(
"path".to_string(),
UntaggedValue::filepath(f.path).into_value(&f.tag),
);
r.insert(
"apparent".to_string(),
UntaggedValue::filesize(f.size).into_value(&f.tag),
);
let b = f
.blocks
.map(UntaggedValue::filesize)
.unwrap_or_else(UntaggedValue::nothing)
.into_value(&f.tag);
r.insert("physical".to_string(), b);
r.insert(
"directories".to_string(),
UntaggedValue::nothing().into_value(&f.tag),
);
r.insert(
"files".to_string(),
UntaggedValue::nothing().into_value(&f.tag),
);
UntaggedValue::row(r).into_value(&f.tag)
}
}
#[cfg(test)]
mod tests {
use super::Du;

View File

@ -1,6 +1,6 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use futures::stream::once;
use nu_errors::ShellError;

View File

@ -1,6 +1,6 @@
use crate::commands::each::process_row;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,

View File

@ -1,6 +1,6 @@
use crate::commands::each::group::run_block_on_vec;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
//use itertools::Itertools;
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, Primitive, Signature, SyntaxShape, UntaggedValue};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::hir::Operator;
use nu_protocol::{

View File

@ -1,6 +1,6 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape,

View File

@ -1,6 +1,6 @@
use crate::commands::UnevaluatedCallInfo;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::UnevaluatedCallInfo;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::hir::ExternalRedirection;
use nu_protocol::{

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;

View File

@ -1,4 +1,3 @@
use crate::commands::command::WholeStreamCommand;
use crate::prelude::*;
use nu_errors::ShellError;
use nu_protocol::{CommandAction, ReturnSuccess, Signature};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
Dictionary, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*;
use nu_engine::evaluate_baseline_expr;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,7 +1,7 @@
use crate::prelude::*;
use nu_errors::ShellError;
use crate::commands::WholeStreamCommand;
use nu_engine::WholeStreamCommand;
use nu_protocol::{
ColumnPath, Primitive::Filesize, ReturnSuccess, Signature, SyntaxShape, UntaggedValue,
UntaggedValue::Primitive, Value,

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
@ -21,8 +21,7 @@ impl WholeStreamCommand for From {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&From, &args.scope))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&From, &args.scope)).into_value(Tag::unknown()),
)))
}
}

View File

@ -1,6 +1,6 @@
use crate::commands::from_delimited_data::from_delimited_data;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use ::eml_parser::eml::*;
use ::eml_parser::EmlParser;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,8 +1,8 @@
extern crate ical;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use ical::parser::ical::component::*;
use ical::property::Property;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};
use std::io::BufReader;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, Signature, TaggedDictBuilder, UntaggedValue, Value};
use std::collections::HashMap;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use calamine::*;
use nu_data::TaggedListBuilder;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue};
use std::io::Cursor;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
Primitive, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};

View File

@ -1,6 +1,6 @@
use crate::commands::from_delimited_data::from_delimited_data;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::Signature;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue};

View File

@ -1,8 +1,8 @@
extern crate ical;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use ical::parser::vcard::component::*;
use ical::property::Property;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use calamine::*;
use nu_data::TaggedListBuilder;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue};
use std::io::Cursor;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, TaggedDictBuilder, UntaggedValue, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, Signature, TaggedDictBuilder, UntaggedValue, Value};

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use indexmap::set::IndexSet;
use log::trace;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
did_you_mean, ColumnPath, Dictionary, PathMember, Primitive, ReturnSuccess, Signature,

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use crate::utils::suggestions::suggestions;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,6 +1,6 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use crate::utils::suggestions::suggestions;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::ShellTypeName;
use nu_protocol::{

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue};
@ -24,8 +24,7 @@ impl WholeStreamCommand for Command {
async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(OutputStream::one(ReturnSuccess::value(
UntaggedValue::string(crate::commands::help::get_help(&Command, &args.scope))
.into_value(Tag::unknown()),
UntaggedValue::string(get_help(&Command, &args.scope)).into_value(Tag::unknown()),
)))
}
}

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use futures::stream::StreamExt;
use indexmap::IndexMap;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::Dictionary;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};

View File

@ -1,8 +1,7 @@
use crate::commands::command::Command;
use crate::commands::WholeStreamCommand;
use crate::documentation::{generate_docs, get_documentation, DocumentationConfig};
use crate::prelude::*;
use nu_data::command::signature_dict;
use nu_engine::command_dict;
use nu_engine::documentation::generate_docs;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value};
use nu_source::{SpannedItem, Tagged};
@ -34,21 +33,6 @@ impl WholeStreamCommand for Help {
}
}
pub(crate) fn command_dict(command: Command, tag: impl Into<Tag>) -> Value {
let tag = tag.into();
let mut cmd_dict = TaggedDictBuilder::new(&tag);
cmd_dict.insert_untagged("name", UntaggedValue::string(command.name()));
cmd_dict.insert_untagged("type", UntaggedValue::string("Command"));
cmd_dict.insert_value("signature", signature_dict(command.signature(), tag));
cmd_dict.insert_untagged("usage", UntaggedValue::string(command.usage()));
cmd_dict.into_value()
}
async fn help(args: CommandArgs) -> Result<OutputStream, ShellError> {
let name = args.call_info.name_tag.clone();
let scope = args.scope.clone();
@ -224,10 +208,6 @@ You can also learn more at https://www.nushell.sh/book/"#;
}
}
pub fn get_help(cmd: &dyn WholeStreamCommand, scope: &Scope) -> String {
get_documentation(cmd, scope, &DocumentationConfig::default())
}
#[cfg(test)]
mod tests {
use super::Help;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
ColumnPath, ReturnSuccess, Signature, SyntaxShape, TaggedDictBuilder, UntaggedValue, Value,

View File

@ -1,31 +1,11 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_data::config::{Conf, NuConfig};
use nu_engine::history_path;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, UntaggedValue};
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
const DEFAULT_LOCATION: &str = "history.txt";
pub fn history_path(config: &dyn Conf) -> PathBuf {
let default_path = nu_data::config::user_data()
.map(|mut p| {
p.push(DEFAULT_LOCATION);
p
})
.unwrap_or_else(|_| PathBuf::from(DEFAULT_LOCATION));
config
.var("history-path")
.map_or(default_path.clone(), |custom_path| {
match custom_path.as_string() {
Ok(path) => PathBuf::from(path),
Err(_) => default_path,
}
})
}
#[derive(Deserialize)]
struct Arguments {

View File

@ -1,7 +1,7 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*;
use nu_engine::evaluate_baseline_expr;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
hir::CapturedBlock, hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue,

View File

@ -1,6 +1,6 @@
use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::run_block;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{
ColumnPath, Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value,

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged;

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*;
use log::trace;
use nu_engine::evaluate_baseline_expr;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_parser::ParserScope;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,7 +1,7 @@
use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*;
use log::trace;
use nu_engine::evaluate_baseline_expr;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape, UntaggedValue, Value};
use nu_source::Tagged;

View File

@ -1,5 +1,5 @@
use crate::prelude::*;
use crate::{commands::WholeStreamCommand, evaluate::evaluate_baseline_expr};
use nu_engine::{evaluate_baseline_expr, WholeStreamCommand};
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, hir::ClassifiedCommand, Signature, SyntaxShape};

View File

@ -1,5 +1,5 @@
use crate::prelude::*;
use crate::{commands::WholeStreamCommand, evaluate::evaluate_baseline_expr};
use nu_engine::{evaluate_baseline_expr, WholeStreamCommand};
use nu_errors::ShellError;
use nu_protocol::{hir::CapturedBlock, hir::ClassifiedCommand, Signature, SyntaxShape};

View File

@ -1,5 +1,5 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Primitive, ReturnSuccess, Signature, UntaggedValue, Value};
use parking_lot::Mutex;

View File

@ -1,23 +1,10 @@
use crate::commands::WholeStreamCommand;
use crate::prelude::*;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{Signature, SyntaxShape};
use nu_source::Tagged;
use std::path::PathBuf;
pub struct Ls;
#[derive(Deserialize)]
pub struct LsArgs {
pub path: Option<Tagged<PathBuf>>,
pub all: bool,
pub long: bool,
#[serde(rename = "short-names")]
pub short_names: bool,
#[serde(rename = "du")]
pub du: bool,
}
#[async_trait]
impl WholeStreamCommand for Ls {
fn name(&self) -> &str {

Some files were not shown because too many files have changed in this diff Show More