2019-11-21 17:18:00 +00:00
|
|
|
use crate::data::value;
|
2019-11-24 22:19:12 +00:00
|
|
|
use crate::prelude::*;
|
|
|
|
use derive_new::new;
|
|
|
|
use log::{log_enabled, trace};
|
2019-11-21 17:18:00 +00:00
|
|
|
use nu_errors::ShellError;
|
|
|
|
use nu_parser::hir;
|
|
|
|
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
|
2019-11-24 22:19:12 +00:00
|
|
|
|
|
|
|
use super::ClassifiedInputStream;
|
|
|
|
|
|
|
|
#[derive(new, Debug, Clone, Eq, PartialEq)]
|
2019-11-26 03:25:12 +00:00
|
|
|
pub struct Command {
|
2019-11-24 22:19:12 +00:00
|
|
|
pub(crate) name: String,
|
|
|
|
pub(crate) name_tag: Tag,
|
2019-11-26 03:25:12 +00:00
|
|
|
pub(crate) args: hir::Call,
|
2019-11-24 22:19:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl HasSpan for Command {
|
|
|
|
fn span(&self) -> Span {
|
|
|
|
let start = self.name_tag.span;
|
|
|
|
|
|
|
|
start.until(self.args.span)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-26 03:25:12 +00:00
|
|
|
impl PrettyDebugWithSource for Command {
|
|
|
|
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
|
|
|
b::typed(
|
|
|
|
"internal command",
|
|
|
|
b::description(&self.name) + b::space() + self.args.pretty_debug(source),
|
|
|
|
)
|
2019-11-24 22:19:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Command {
|
|
|
|
pub(crate) fn run(
|
|
|
|
self,
|
|
|
|
context: &mut Context,
|
|
|
|
input: ClassifiedInputStream,
|
|
|
|
source: Text,
|
|
|
|
) -> Result<InputStream, ShellError> {
|
|
|
|
if log_enabled!(log::Level::Trace) {
|
|
|
|
trace!(target: "nu::run::internal", "->");
|
|
|
|
trace!(target: "nu::run::internal", "{}", self.name);
|
|
|
|
trace!(target: "nu::run::internal", "{}", self.args.debug(&source));
|
|
|
|
}
|
|
|
|
|
2019-11-26 03:25:12 +00:00
|
|
|
let objects: InputStream =
|
|
|
|
trace_stream!(target: "nu::trace_stream::internal", "input" = input.objects);
|
2019-11-24 22:19:12 +00:00
|
|
|
|
|
|
|
let command = context.expect_command(&self.name);
|
|
|
|
|
2019-11-26 03:25:12 +00:00
|
|
|
let result =
|
|
|
|
{ context.run_command(command, self.name_tag.clone(), self.args, &source, objects) };
|
2019-11-24 22:19:12 +00:00
|
|
|
|
2019-11-26 03:25:12 +00:00
|
|
|
let result = trace_out_stream!(target: "nu::trace_stream::internal", "output" = result);
|
2019-11-24 22:19:12 +00:00
|
|
|
let mut result = result.values;
|
|
|
|
let mut context = context.clone();
|
|
|
|
|
|
|
|
let stream = async_stream! {
|
|
|
|
let mut soft_errs: Vec<ShellError> = vec![];
|
|
|
|
let mut yielded = false;
|
|
|
|
|
|
|
|
while let Some(item) = result.next().await {
|
|
|
|
match item {
|
|
|
|
Ok(ReturnSuccess::Action(action)) => match action {
|
|
|
|
CommandAction::ChangePath(path) => {
|
|
|
|
context.shell_manager.set_path(path);
|
|
|
|
}
|
|
|
|
CommandAction::Exit => std::process::exit(0), // TODO: save history.txt
|
|
|
|
CommandAction::Error(err) => {
|
|
|
|
context.error(err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
CommandAction::EnterHelpShell(value) => {
|
|
|
|
match value {
|
2019-11-26 03:25:12 +00:00
|
|
|
Value {
|
|
|
|
value: UntaggedValue::Primitive(Primitive::String(cmd)),
|
2019-11-24 22:19:12 +00:00
|
|
|
tag,
|
|
|
|
} => {
|
|
|
|
context.shell_manager.insert_at_current(Box::new(
|
|
|
|
HelpShell::for_command(
|
2019-11-21 17:18:00 +00:00
|
|
|
value::string(cmd).into_value(tag),
|
2019-11-24 22:19:12 +00:00
|
|
|
&context.registry(),
|
|
|
|
).unwrap(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
context.shell_manager.insert_at_current(Box::new(
|
|
|
|
HelpShell::index(&context.registry()).unwrap(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CommandAction::EnterValueShell(value) => {
|
|
|
|
context
|
|
|
|
.shell_manager
|
|
|
|
.insert_at_current(Box::new(ValueShell::new(value)));
|
|
|
|
}
|
|
|
|
CommandAction::EnterShell(location) => {
|
|
|
|
context.shell_manager.insert_at_current(Box::new(
|
|
|
|
FilesystemShell::with_location(location, context.registry().clone()).unwrap(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
CommandAction::PreviousShell => {
|
|
|
|
context.shell_manager.prev();
|
|
|
|
}
|
|
|
|
CommandAction::NextShell => {
|
|
|
|
context.shell_manager.next();
|
|
|
|
}
|
|
|
|
CommandAction::LeaveShell => {
|
|
|
|
context.shell_manager.remove_at_current();
|
|
|
|
if context.shell_manager.is_empty() {
|
|
|
|
std::process::exit(0); // TODO: save history.txt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
Ok(ReturnSuccess::Value(v)) => {
|
|
|
|
yielded = true;
|
|
|
|
yield Ok(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(ReturnSuccess::DebugValue(v)) => {
|
|
|
|
yielded = true;
|
|
|
|
|
2019-11-26 03:25:12 +00:00
|
|
|
let doc = PrettyDebug::pretty_doc(&v);
|
2019-11-24 22:19:12 +00:00
|
|
|
let mut buffer = termcolor::Buffer::ansi();
|
|
|
|
|
|
|
|
doc.render_raw(
|
|
|
|
context.with_host(|host| host.width() - 5),
|
2019-11-21 17:18:00 +00:00
|
|
|
&mut nu_source::TermColored::new(&mut buffer),
|
2019-11-24 22:19:12 +00:00
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
let value = String::from_utf8_lossy(buffer.as_slice());
|
|
|
|
|
2019-11-21 17:18:00 +00:00
|
|
|
yield Ok(value::string(value).into_untagged_value())
|
2019-11-24 22:19:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Err(err) => {
|
|
|
|
context.error(err);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(stream.to_input_stream())
|
|
|
|
}
|
|
|
|
}
|