mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 19:37:45 +02:00
Restructure and streamline token expansion (#1123)
Restructure and streamline token expansion The purpose of this commit is to streamline the token expansion code, by removing aspects of the code that are no longer relevant, removing pointless duplication, and eliminating the need to pass the same arguments to `expand_syntax`. The first big-picture change in this commit is that instead of a handful of `expand_` functions, which take a TokensIterator and ExpandContext, a smaller number of methods on the `TokensIterator` do the same job. The second big-picture change in this commit is fully eliminating the coloring traits, making coloring a responsibility of the base expansion implementations. This also means that the coloring tracer is merged into the expansion tracer, so you can follow a single expansion and see how the expansion process produced colored tokens. One side effect of this change is that the expander itself is marginally more error-correcting. The error correction works by switching from structured expansion to `BackoffColoringMode` when an unexpected token is found, which guarantees that all spans of the source are colored, but may not be the most optimal error recovery strategy. That said, because `BackoffColoringMode` only extends as far as a closing delimiter (`)`, `]`, `}`) or pipe (`|`), it does result in fairly granular correction strategy. The current code still produces an `Err` (plus a complete list of colored shapes) from the parsing process if any errors are encountered, but this could easily be addressed now that the underlying expansion is error-correcting. This commit also colors any spans that are syntax errors in red, and causes the parser to include some additional information about what tokens were expected at any given point where an error was encountered, so that completions and hinting could be more robust in the future. Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com> Co-authored-by: Andrés N. Robalino <andres@androbtech.com>
This commit is contained in:
committed by
Andrés N. Robalino
parent
c8dd7838a8
commit
7efb31a4e4
64
src/cli.rs
64
src/cli.rs
@ -8,9 +8,10 @@ use crate::data::config;
|
||||
use crate::git::current_branch;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::hir::Expression;
|
||||
use nu_parser::{
|
||||
expand_syntax, hir, ClassifiedCommand, ClassifiedPipeline, InternalCommand, PipelineShape,
|
||||
TokenNode, TokensIterator,
|
||||
hir, ClassifiedCommand, ClassifiedPipeline, InternalCommand, PipelineShape, SpannedToken,
|
||||
TokensIterator,
|
||||
};
|
||||
use nu_protocol::{Signature, UntaggedValue, Value};
|
||||
|
||||
@ -60,16 +61,16 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
|
||||
let name = params.name.clone();
|
||||
let fname = fname.to_string();
|
||||
|
||||
if context.get_command(&name)?.is_some() {
|
||||
if context.get_command(&name).is_some() {
|
||||
trace!("plugin {:?} already loaded.", &name);
|
||||
} else if params.is_filter {
|
||||
context.add_commands(vec![whole_stream_command(
|
||||
PluginCommand::new(name, fname, params),
|
||||
)])?;
|
||||
context.add_commands(vec![whole_stream_command(PluginCommand::new(
|
||||
name, fname, params,
|
||||
))]);
|
||||
} else {
|
||||
context.add_commands(vec![whole_stream_command(PluginSink::new(
|
||||
name, fname, params,
|
||||
))])?;
|
||||
))]);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -346,7 +347,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
whole_stream_command(FromXML),
|
||||
whole_stream_command(FromYAML),
|
||||
whole_stream_command(FromYML),
|
||||
])?;
|
||||
]);
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(data_processing_primitives)] {
|
||||
@ -355,7 +356,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
whole_stream_command(EvaluateBy),
|
||||
whole_stream_command(TSortBy),
|
||||
whole_stream_command(MapMaxBy),
|
||||
])?;
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,7 +364,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
{
|
||||
context.add_commands(vec![whole_stream_command(
|
||||
crate::commands::clip::clipboard::Clip,
|
||||
)])?;
|
||||
)]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -402,7 +403,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
continue;
|
||||
}
|
||||
|
||||
let cwd = context.shell_manager.path()?;
|
||||
let cwd = context.shell_manager.path();
|
||||
|
||||
rl.set_helper(Some(crate::shell::Helper::new(context.clone())));
|
||||
|
||||
@ -479,7 +480,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
context.with_host(|host| {
|
||||
print_err(err, host, &Text::from(line.clone()));
|
||||
})?;
|
||||
});
|
||||
|
||||
context.maybe_print_errors(Text::from(line.clone()));
|
||||
}
|
||||
@ -501,7 +502,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||
let _ = rl.save_history(&History::path());
|
||||
std::process::exit(0);
|
||||
} else {
|
||||
context.with_host(|host| host.stdout("CTRL-C pressed (again to quit)"))?;
|
||||
context.with_host(|host| host.stdout("CTRL-C pressed (again to quit)"));
|
||||
ctrlcbreak = true;
|
||||
continue;
|
||||
}
|
||||
@ -606,26 +607,33 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
debug!("=== Parsed ===");
|
||||
debug!("{:#?}", result);
|
||||
|
||||
let mut pipeline = match classify_pipeline(&result, ctx, &Text::from(line)) {
|
||||
Ok(pipeline) => pipeline,
|
||||
Err(err) => return LineResult::Error(line.to_string(), err),
|
||||
let mut pipeline = classify_pipeline(&result, ctx, &Text::from(line));
|
||||
|
||||
if let Some(failure) = pipeline.failed {
|
||||
return LineResult::Error(line.to_string(), failure.into());
|
||||
}
|
||||
|
||||
let should_push = match pipeline.commands.list.last() {
|
||||
Some(ClassifiedCommand::External(_)) => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
match pipeline.commands.list.last() {
|
||||
Some(ClassifiedCommand::External(_)) => {}
|
||||
_ => pipeline
|
||||
if should_push {
|
||||
pipeline
|
||||
.commands
|
||||
.list
|
||||
.push(ClassifiedCommand::Internal(InternalCommand {
|
||||
name: "autoview".to_string(),
|
||||
name_tag: Tag::unknown(),
|
||||
args: hir::Call::new(
|
||||
Box::new(hir::Expression::synthetic_string("autoview")),
|
||||
Box::new(
|
||||
Expression::synthetic_string("autoview").into_expr(Span::unknown()),
|
||||
),
|
||||
None,
|
||||
None,
|
||||
Span::unknown(),
|
||||
),
|
||||
})),
|
||||
}));
|
||||
}
|
||||
|
||||
// Check the config to see if we need to update the path
|
||||
@ -650,19 +658,15 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
|
||||
}
|
||||
|
||||
pub fn classify_pipeline(
|
||||
pipeline: &TokenNode,
|
||||
pipeline: &SpannedToken,
|
||||
context: &Context,
|
||||
source: &Text,
|
||||
) -> Result<ClassifiedPipeline, ShellError> {
|
||||
) -> ClassifiedPipeline {
|
||||
let pipeline_list = vec![pipeline.clone()];
|
||||
let mut iterator = TokensIterator::all(&pipeline_list, source.clone(), pipeline.span());
|
||||
let expand_context = context.expand_context(source);
|
||||
let mut iterator = TokensIterator::new(&pipeline_list, expand_context, pipeline.span());
|
||||
|
||||
let result = expand_syntax(
|
||||
&PipelineShape,
|
||||
&mut iterator,
|
||||
&context.expand_context(source)?,
|
||||
)
|
||||
.map_err(|err| err.into());
|
||||
let result = iterator.expand_infallible(PipelineShape);
|
||||
|
||||
if log_enabled!(target: "nu::expand_syntax", log::Level::Debug) {
|
||||
outln!("");
|
||||
|
@ -70,7 +70,7 @@ pub fn autoview(
|
||||
}
|
||||
}
|
||||
};
|
||||
if let Some(table) = table? {
|
||||
if let Some(table) = table {
|
||||
let mut new_output_stream: OutputStream = stream.to_output_stream();
|
||||
let mut finished = false;
|
||||
let mut current_idx = 0;
|
||||
@ -100,7 +100,7 @@ pub fn autoview(
|
||||
let first = &input[0];
|
||||
|
||||
let mut host = context.host.clone();
|
||||
let mut host = host.lock();
|
||||
let host = host.lock();
|
||||
|
||||
crate::cli::print_err(first.value.expect_error(), &*host, &context.source);
|
||||
return;
|
||||
@ -108,13 +108,12 @@ pub fn autoview(
|
||||
|
||||
let mut command_args = raw.with_input(input);
|
||||
let mut named_args = NamedArguments::new();
|
||||
named_args.insert_optional("start_number", Some(Expression::number(current_idx, Tag::unknown())));
|
||||
named_args.insert_optional("start_number", Some(Expression::number(current_idx).into_expr(Span::unknown())));
|
||||
command_args.call_info.args.named = Some(named_args);
|
||||
|
||||
let result = table.run(command_args, &context.commands);
|
||||
result.collect::<Vec<_>>().await;
|
||||
|
||||
|
||||
if finished {
|
||||
break;
|
||||
} else {
|
||||
@ -130,7 +129,7 @@ pub fn autoview(
|
||||
value: UntaggedValue::Primitive(Primitive::String(ref s)),
|
||||
tag: Tag { anchor, span },
|
||||
} if anchor.is_some() => {
|
||||
if let Some(text) = text? {
|
||||
if let Some(text) = text {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span }));
|
||||
let result = text.run(raw.with_input(stream.into()), &context.commands);
|
||||
@ -149,7 +148,7 @@ pub fn autoview(
|
||||
value: UntaggedValue::Primitive(Primitive::Line(ref s)),
|
||||
tag: Tag { anchor, span },
|
||||
} if anchor.is_some() => {
|
||||
if let Some(text) = text? {
|
||||
if let Some(text) = text {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span }));
|
||||
let result = text.run(raw.with_input(stream.into()), &context.commands);
|
||||
@ -184,7 +183,7 @@ pub fn autoview(
|
||||
}
|
||||
|
||||
Value { value: UntaggedValue::Primitive(Primitive::Binary(ref b)), .. } => {
|
||||
if let Some(binary) = binary? {
|
||||
if let Some(binary) = binary {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(x);
|
||||
let result = binary.run(raw.with_input(stream.into()), &context.commands);
|
||||
@ -199,7 +198,7 @@ pub fn autoview(
|
||||
yield Err(e);
|
||||
}
|
||||
Value { value: ref item, .. } => {
|
||||
if let Some(table) = table? {
|
||||
if let Some(table) = table {
|
||||
let mut stream = VecDeque::new();
|
||||
stream.push_back(x);
|
||||
let result = table.run(raw.with_input(stream.into()), &context.commands);
|
||||
|
@ -102,7 +102,7 @@ async fn run_with_iterator_arg(
|
||||
input: Option<InputStream>,
|
||||
is_last: bool,
|
||||
) -> Result<Option<InputStream>, ShellError> {
|
||||
let path = context.shell_manager.path()?;
|
||||
let path = context.shell_manager.path();
|
||||
|
||||
let mut inputs: InputStream = if let Some(input) = input {
|
||||
trace_stream!(target: "nu::trace_stream::external::it", "input" = input)
|
||||
@ -180,7 +180,7 @@ async fn run_with_stdin(
|
||||
input: Option<InputStream>,
|
||||
is_last: bool,
|
||||
) -> Result<Option<InputStream>, ShellError> {
|
||||
let path = context.shell_manager.path()?;
|
||||
let path = context.shell_manager.path();
|
||||
|
||||
let mut inputs: InputStream = if let Some(input) = input {
|
||||
trace_stream!(target: "nu::trace_stream::external::stdin", "input" = input)
|
||||
|
@ -47,18 +47,18 @@ pub(crate) async fn run_internal_command(
|
||||
match item {
|
||||
Ok(ReturnSuccess::Action(action)) => match action {
|
||||
CommandAction::ChangePath(path) => {
|
||||
context.shell_manager.set_path(path)?;
|
||||
context.shell_manager.set_path(path);
|
||||
}
|
||||
CommandAction::Exit => std::process::exit(0), // TODO: save history.txt
|
||||
CommandAction::Error(err) => {
|
||||
context.error(err)?;
|
||||
context.error(err);
|
||||
break;
|
||||
}
|
||||
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.registry.get_command(&command_name)? {
|
||||
if let Some(converter) = context.registry.get_command(&command_name) {
|
||||
let new_args = RawCommandArgs {
|
||||
host: context.host.clone(),
|
||||
ctrl_c: context.ctrl_c.clone(),
|
||||
@ -100,43 +100,39 @@ pub(crate) async fn run_internal_command(
|
||||
value: UntaggedValue::Primitive(Primitive::String(cmd)),
|
||||
tag,
|
||||
} => {
|
||||
let result = context.shell_manager.insert_at_current(Box::new(
|
||||
context.shell_manager.insert_at_current(Box::new(
|
||||
HelpShell::for_command(
|
||||
UntaggedValue::string(cmd).into_value(tag),
|
||||
&context.registry(),
|
||||
)?,
|
||||
));
|
||||
|
||||
result?
|
||||
}
|
||||
_ => {
|
||||
let result = context.shell_manager.insert_at_current(Box::new(
|
||||
context.shell_manager.insert_at_current(Box::new(
|
||||
HelpShell::index(&context.registry())?,
|
||||
));
|
||||
|
||||
result?
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandAction::EnterValueShell(value) => {
|
||||
context
|
||||
.shell_manager
|
||||
.insert_at_current(Box::new(ValueShell::new(value)))?;
|
||||
.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()),
|
||||
))?;
|
||||
));
|
||||
}
|
||||
CommandAction::PreviousShell => {
|
||||
context.shell_manager.prev()?;
|
||||
context.shell_manager.prev();
|
||||
}
|
||||
CommandAction::NextShell => {
|
||||
context.shell_manager.next()?;
|
||||
context.shell_manager.next();
|
||||
}
|
||||
CommandAction::LeaveShell => {
|
||||
context.shell_manager.remove_at_current()?;
|
||||
if context.shell_manager.is_empty()? {
|
||||
context.shell_manager.remove_at_current();
|
||||
if context.shell_manager.is_empty() {
|
||||
std::process::exit(0); // TODO: save history.txt
|
||||
}
|
||||
}
|
||||
@ -154,7 +150,7 @@ pub(crate) async fn run_internal_command(
|
||||
let mut buffer = termcolor::Buffer::ansi();
|
||||
|
||||
let _ = doc.render_raw(
|
||||
context.with_host(|host| host.width() - 5)?,
|
||||
context.with_host(|host| host.width() - 5),
|
||||
&mut nu_source::TermColored::new(&mut buffer),
|
||||
);
|
||||
|
||||
@ -164,7 +160,7 @@ pub(crate) async fn run_internal_command(
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
context.error(err)?;
|
||||
context.error(err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,9 @@ pub(crate) async fn run_pipeline(
|
||||
return Err(ShellError::unimplemented("Expression-only commands"))
|
||||
}
|
||||
|
||||
(Some(ClassifiedCommand::Error(err)), _) => return Err(err.into()),
|
||||
(_, Some(ClassifiedCommand::Error(err))) => return Err(err.clone().into()),
|
||||
|
||||
(Some(ClassifiedCommand::Internal(left)), _) => {
|
||||
run_internal_command(left, ctx, input, Text::from(line)).await?
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ pub struct RunnableContext {
|
||||
}
|
||||
|
||||
impl RunnableContext {
|
||||
pub fn get_command(&self, name: &str) -> Result<Option<Arc<Command>>, ShellError> {
|
||||
pub fn get_command(&self, name: &str) -> Option<Arc<Command>> {
|
||||
self.commands.get_command(name)
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ impl PerItemCommand for Enter {
|
||||
if spec.len() == 2 {
|
||||
let (_, command) = (spec[0], spec[1]);
|
||||
|
||||
if registry.has(command)? {
|
||||
if registry.has(command) {
|
||||
return Ok(vec![Ok(ReturnSuccess::Action(
|
||||
CommandAction::EnterHelpShell(
|
||||
UntaggedValue::string(command).into_value(Tag::unknown()),
|
||||
@ -74,7 +74,7 @@ impl PerItemCommand for Enter {
|
||||
// If it's a file, attempt to open the file as a value and enter it
|
||||
let cwd = raw_args.shell_manager.path();
|
||||
|
||||
let full_path = std::path::PathBuf::from(cwd?);
|
||||
let full_path = std::path::PathBuf::from(cwd);
|
||||
|
||||
let (file_extension, contents, contents_tag) =
|
||||
crate::commands::open::fetch(
|
||||
@ -90,7 +90,7 @@ impl PerItemCommand for Enter {
|
||||
if let Some(extension) = file_extension {
|
||||
let command_name = format!("from-{}", extension);
|
||||
if let Some(converter) =
|
||||
registry.get_command(&command_name)?
|
||||
registry.get_command(&command_name)
|
||||
{
|
||||
let new_args = RawCommandArgs {
|
||||
host: raw_args.host,
|
||||
|
@ -153,7 +153,8 @@ fn from_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputSt
|
||||
}
|
||||
_ => yield ReturnSuccess::value(x),
|
||||
}
|
||||
Err(_) => {
|
||||
Err(err) => {
|
||||
println!("{:?}", err);
|
||||
yield Err(ShellError::labeled_error_with_secondary(
|
||||
"Could not parse as SQLite",
|
||||
"input cannot be parsed as SQLite",
|
||||
|
@ -41,12 +41,12 @@ impl PerItemCommand for Help {
|
||||
}) => {
|
||||
let mut help = VecDeque::new();
|
||||
if document == "commands" {
|
||||
let mut sorted_names = registry.names()?;
|
||||
let mut sorted_names = registry.names();
|
||||
sorted_names.sort();
|
||||
for cmd in sorted_names {
|
||||
let mut short_desc = TaggedDictBuilder::new(tag.clone());
|
||||
let value = command_dict(
|
||||
registry.get_command(&cmd)?.ok_or_else(|| {
|
||||
registry.get_command(&cmd).ok_or_else(|| {
|
||||
ShellError::labeled_error(
|
||||
format!("Could not load {}", cmd),
|
||||
"could not load command",
|
||||
@ -72,7 +72,7 @@ impl PerItemCommand for Help {
|
||||
|
||||
help.push_back(ReturnSuccess::value(short_desc.into_value()));
|
||||
}
|
||||
} else if let Some(command) = registry.get_command(document)? {
|
||||
} else if let Some(command) = registry.get_command(document) {
|
||||
return Ok(
|
||||
get_help(&command.name(), &command.usage(), command.signature()).into(),
|
||||
);
|
||||
|
@ -40,7 +40,7 @@ impl PerItemCommand for Open {
|
||||
|
||||
fn run(call_info: &CallInfo, raw_args: &RawCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let shell_manager = &raw_args.shell_manager;
|
||||
let cwd = PathBuf::from(shell_manager.path()?);
|
||||
let cwd = PathBuf::from(shell_manager.path());
|
||||
let full_path = cwd;
|
||||
|
||||
let path = call_info.args.nth(0).ok_or_else(|| {
|
||||
|
@ -130,7 +130,7 @@ fn save(
|
||||
}: RunnableContext,
|
||||
raw_args: RawCommandArgs,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let mut full_path = PathBuf::from(shell_manager.path()?);
|
||||
let mut full_path = PathBuf::from(shell_manager.path());
|
||||
let name_tag = name.clone();
|
||||
|
||||
let stream = async_stream! {
|
||||
@ -179,7 +179,7 @@ fn save(
|
||||
break if !save_raw {
|
||||
if let Some(extension) = full_path.extension() {
|
||||
let command_name = format!("to-{}", extension.to_string_lossy());
|
||||
if let Some(converter) = registry.get_command(&command_name)? {
|
||||
if let Some(converter) = registry.get_command(&command_name) {
|
||||
let new_args = RawCommandArgs {
|
||||
host,
|
||||
ctrl_c,
|
||||
|
@ -32,16 +32,7 @@ fn shells(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream
|
||||
let mut shells_out = VecDeque::new();
|
||||
let tag = args.call_info.name_tag;
|
||||
|
||||
for (index, shell) in args
|
||||
.shell_manager
|
||||
.shells
|
||||
.lock()
|
||||
.map_err(|_| {
|
||||
ShellError::labeled_error("Could not list shells", "could not list shells", &tag)
|
||||
})?
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
for (index, shell) in args.shell_manager.shells.lock().iter().enumerate() {
|
||||
let mut dict = TaggedDictBuilder::new(&tag);
|
||||
|
||||
if index == (*args.shell_manager.current_shell).load(Ordering::SeqCst) {
|
||||
|
@ -5,7 +5,6 @@ use futures::StreamExt;
|
||||
use futures_util::pin_mut;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{ReturnSuccess, ReturnValue, Signature, UntaggedValue};
|
||||
use nu_source::PrettyDebug;
|
||||
|
||||
pub struct What;
|
||||
|
||||
@ -14,11 +13,11 @@ pub struct WhatArgs {}
|
||||
|
||||
impl WholeStreamCommand for What {
|
||||
fn name(&self) -> &str {
|
||||
"what?"
|
||||
"describe"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("what?")
|
||||
Signature::build("describe")
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
@ -43,7 +42,7 @@ pub fn what(
|
||||
pin_mut!(values);
|
||||
|
||||
while let Some(row) = values.next().await {
|
||||
let name = value::format_leaf(&row).plain_string(100000);
|
||||
let name = value::format_type(&row, 100);
|
||||
yield ReturnSuccess::value(UntaggedValue::string(name).into_value(Tag::unknown_anchor(row.tag.span)));
|
||||
}
|
||||
};
|
||||
|
@ -95,7 +95,7 @@ fn which(
|
||||
}
|
||||
}
|
||||
|
||||
let builtin = commands.has(&item)?;
|
||||
let builtin = commands.has(&item);
|
||||
if builtin {
|
||||
yield ReturnSuccess::value(entry_builtin!(item, application.tag.clone()));
|
||||
}
|
||||
@ -128,7 +128,7 @@ fn which(
|
||||
if let Ok(path) = ichwh::which(&item).await {
|
||||
yield ReturnSuccess::value(entry_path!(item, path.into(), application.tag.clone()));
|
||||
}
|
||||
} else if commands.has(&item)? {
|
||||
} else if commands.has(&item) {
|
||||
yield ReturnSuccess::value(entry_builtin!(item, application.tag.clone()));
|
||||
} else if let Ok(path) = ichwh::which(&item).await {
|
||||
yield ReturnSuccess::value(entry_path!(item, path.into(), application.tag.clone()));
|
||||
|
159
src/context.rs
159
src/context.rs
@ -5,37 +5,29 @@ use crate::stream::{InputStream, OutputStream};
|
||||
use indexmap::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::{hir, hir::syntax_shape::ExpandContext, hir::syntax_shape::SignatureRegistry};
|
||||
use nu_protocol::{errln, Signature};
|
||||
use nu_protocol::Signature;
|
||||
use nu_source::{Tag, Text};
|
||||
use parking_lot::Mutex;
|
||||
use std::error::Error;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CommandRegistry {
|
||||
registry: Arc<Mutex<IndexMap<String, Arc<Command>>>>,
|
||||
}
|
||||
|
||||
impl SignatureRegistry for CommandRegistry {
|
||||
fn has(&self, name: &str) -> Result<bool, ShellError> {
|
||||
if let Ok(registry) = self.registry.lock() {
|
||||
Ok(registry.contains_key(name))
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(format!(
|
||||
"Could not load from registry: {}",
|
||||
name
|
||||
)))
|
||||
}
|
||||
fn has(&self, name: &str) -> bool {
|
||||
let registry = self.registry.lock();
|
||||
registry.contains_key(name)
|
||||
}
|
||||
fn get(&self, name: &str) -> Result<Option<Signature>, ShellError> {
|
||||
if let Ok(registry) = self.registry.lock() {
|
||||
Ok(registry.get(name).map(|command| command.signature()))
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(format!(
|
||||
"Could not get from registry: {}",
|
||||
name
|
||||
)))
|
||||
}
|
||||
fn get(&self, name: &str) -> Option<Signature> {
|
||||
let registry = self.registry.lock();
|
||||
registry.get(name).map(|command| command.signature())
|
||||
}
|
||||
fn clone_box(&self) -> Box<dyn SignatureRegistry> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,53 +46,32 @@ impl CommandRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_command(&self, name: &str) -> Result<Option<Arc<Command>>, ShellError> {
|
||||
let registry = self.registry.lock().map_err(|_| {
|
||||
ShellError::untagged_runtime_error("Internal error: get_command could not get mutex")
|
||||
})?;
|
||||
pub(crate) fn get_command(&self, name: &str) -> Option<Arc<Command>> {
|
||||
let registry = self.registry.lock();
|
||||
|
||||
Ok(registry.get(name).cloned())
|
||||
registry.get(name).cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn expect_command(&self, name: &str) -> Result<Arc<Command>, ShellError> {
|
||||
self.get_command(name)?.ok_or_else(|| {
|
||||
self.get_command(name).ok_or_else(|| {
|
||||
ShellError::untagged_runtime_error(format!("Could not load command: {}", name))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn has(&self, name: &str) -> Result<bool, ShellError> {
|
||||
let registry = self.registry.lock().map_err(|_| {
|
||||
ShellError::untagged_runtime_error("Internal error: has could not get mutex")
|
||||
})?;
|
||||
pub(crate) fn has(&self, name: &str) -> bool {
|
||||
let registry = self.registry.lock();
|
||||
|
||||
Ok(registry.contains_key(name))
|
||||
registry.contains_key(name)
|
||||
}
|
||||
|
||||
pub(crate) fn insert(
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
command: Arc<Command>,
|
||||
) -> Result<(), ShellError> {
|
||||
let mut registry = self.registry.lock().map_err(|_| {
|
||||
ShellError::untagged_runtime_error("Internal error: insert could not get mutex")
|
||||
})?;
|
||||
|
||||
pub(crate) fn insert(&mut self, name: impl Into<String>, command: Arc<Command>) {
|
||||
let mut registry = self.registry.lock();
|
||||
registry.insert(name.into(), command);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn names(&self) -> Result<Vec<String>, ShellError> {
|
||||
let registry = self.registry.lock().map_err(|_| {
|
||||
ShellError::untagged_runtime_error("Internal error: names could not get mutex")
|
||||
})?;
|
||||
Ok(registry.keys().cloned().collect())
|
||||
}
|
||||
|
||||
pub(crate) fn snapshot(&self) -> Result<IndexMap<String, Arc<Command>>, ShellError> {
|
||||
let registry = self.registry.lock().map_err(|_| {
|
||||
ShellError::untagged_runtime_error("Internal error: names could not get mutex")
|
||||
})?;
|
||||
Ok(registry.clone())
|
||||
pub(crate) fn names(&self) -> Vec<String> {
|
||||
let registry = self.registry.lock();
|
||||
registry.keys().cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,12 +92,12 @@ impl Context {
|
||||
pub(crate) fn expand_context<'context>(
|
||||
&'context self,
|
||||
source: &'context Text,
|
||||
) -> Result<ExpandContext<'context>, ShellError> {
|
||||
Ok(ExpandContext::new(
|
||||
) -> ExpandContext {
|
||||
ExpandContext::new(
|
||||
Box::new(self.registry.clone()),
|
||||
source,
|
||||
self.shell_manager.homedir()?,
|
||||
))
|
||||
self.shell_manager.homedir(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn basic() -> Result<Context, Box<dyn Error>> {
|
||||
@ -142,73 +113,47 @@ impl Context {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn error(&mut self, error: ShellError) -> Result<(), ShellError> {
|
||||
pub(crate) fn error(&mut self, error: ShellError) {
|
||||
self.with_errors(|errors| errors.push(error))
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_print_errors(&mut self, source: Text) -> bool {
|
||||
let errors = self.current_errors.clone();
|
||||
let errors = errors.lock();
|
||||
let mut errors = errors.lock();
|
||||
|
||||
let host = self.host.clone();
|
||||
let host = host.lock();
|
||||
|
||||
let result: bool;
|
||||
if errors.len() > 0 {
|
||||
let error = errors[0].clone();
|
||||
*errors = vec![];
|
||||
|
||||
match (errors, host) {
|
||||
(Err(err), _) => {
|
||||
errln!(
|
||||
"Unexpected error attempting to acquire the lock of the current errors: {:?}",
|
||||
err
|
||||
);
|
||||
result = false;
|
||||
}
|
||||
(Ok(mut errors), host) => {
|
||||
if errors.len() > 0 {
|
||||
let error = errors[0].clone();
|
||||
*errors = vec![];
|
||||
|
||||
crate::cli::print_err(error, &*host, &source);
|
||||
result = true;
|
||||
} else {
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub(crate) fn with_host<T>(
|
||||
&mut self,
|
||||
block: impl FnOnce(&mut dyn Host) -> T,
|
||||
) -> Result<T, ShellError> {
|
||||
let mut host = self.host.lock();
|
||||
Ok(block(&mut *host))
|
||||
}
|
||||
|
||||
pub(crate) fn with_errors<T>(
|
||||
&mut self,
|
||||
block: impl FnOnce(&mut Vec<ShellError>) -> T,
|
||||
) -> Result<T, ShellError> {
|
||||
if let Ok(mut errors) = self.current_errors.lock() {
|
||||
Ok(block(&mut *errors))
|
||||
crate::cli::print_err(error, &*host, &source);
|
||||
true
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock host in with_errors",
|
||||
))
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_commands(&mut self, commands: Vec<Arc<Command>>) -> Result<(), ShellError> {
|
||||
pub(crate) fn with_host<T>(&mut self, block: impl FnOnce(&mut dyn Host) -> T) -> T {
|
||||
let mut host = self.host.lock();
|
||||
|
||||
block(&mut *host)
|
||||
}
|
||||
|
||||
pub(crate) fn with_errors<T>(&mut self, block: impl FnOnce(&mut Vec<ShellError>) -> T) -> T {
|
||||
let mut errors = self.current_errors.lock();
|
||||
|
||||
block(&mut *errors)
|
||||
}
|
||||
|
||||
pub fn add_commands(&mut self, commands: Vec<Arc<Command>>) {
|
||||
for command in commands {
|
||||
self.registry.insert(command.name().to_string(), command)?;
|
||||
self.registry.insert(command.name().to_string(), command);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn get_command(&self, name: &str) -> Result<Option<Arc<Command>>, ShellError> {
|
||||
pub(crate) fn get_command(&self, name: &str) -> Option<Arc<Command>> {
|
||||
self.registry.get_command(name)
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ pub struct Operation {
|
||||
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, Serialize, Deserialize, new)]
|
||||
pub struct Block {
|
||||
pub(crate) expressions: Vec<hir::Expression>,
|
||||
pub(crate) expressions: Vec<hir::SpannedExpression>,
|
||||
pub(crate) source: Text,
|
||||
pub(crate) tag: Tag,
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use crate::evaluate::operator::apply_operator;
|
||||
use crate::prelude::*;
|
||||
use log::trace;
|
||||
use nu_errors::{ArgumentError, ShellError};
|
||||
use nu_parser::hir::{self, Expression, RawExpression};
|
||||
use nu_parser::hir::{self, Expression, SpannedExpression};
|
||||
use nu_protocol::{
|
||||
ColumnPath, Evaluate, Primitive, RangeInclusion, Scope, TaggedDictBuilder, UnspannedPathMember,
|
||||
UntaggedValue, Value,
|
||||
@ -12,7 +12,7 @@ use nu_protocol::{
|
||||
use nu_source::Text;
|
||||
|
||||
pub(crate) fn evaluate_baseline_expr(
|
||||
expr: &Expression,
|
||||
expr: &SpannedExpression,
|
||||
registry: &CommandRegistry,
|
||||
scope: &Scope,
|
||||
source: &Text,
|
||||
@ -22,19 +22,19 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
anchor: None,
|
||||
};
|
||||
match &expr.expr {
|
||||
RawExpression::Literal(literal) => Ok(evaluate_literal(literal, source)),
|
||||
RawExpression::ExternalWord => Err(ShellError::argument_error(
|
||||
Expression::Literal(literal) => Ok(evaluate_literal(literal, expr.span, source)),
|
||||
Expression::ExternalWord => Err(ShellError::argument_error(
|
||||
"Invalid external word".spanned(tag.span),
|
||||
ArgumentError::InvalidExternalWord,
|
||||
)),
|
||||
RawExpression::FilePath(path) => Ok(UntaggedValue::path(path.clone()).into_value(tag)),
|
||||
RawExpression::Synthetic(hir::Synthetic::String(s)) => {
|
||||
Expression::FilePath(path) => Ok(UntaggedValue::path(path.clone()).into_value(tag)),
|
||||
Expression::Synthetic(hir::Synthetic::String(s)) => {
|
||||
Ok(UntaggedValue::string(s).into_untagged_value())
|
||||
}
|
||||
RawExpression::Variable(var) => evaluate_reference(var, scope, source, tag),
|
||||
RawExpression::Command(_) => evaluate_command(tag, scope, source),
|
||||
RawExpression::ExternalCommand(external) => evaluate_external(external, scope, source),
|
||||
RawExpression::Binary(binary) => {
|
||||
Expression::Variable(var) => evaluate_reference(var, scope, source, tag),
|
||||
Expression::Command(_) => evaluate_command(tag, scope, source),
|
||||
Expression::ExternalCommand(external) => evaluate_external(external, scope, source),
|
||||
Expression::Binary(binary) => {
|
||||
let left = evaluate_baseline_expr(binary.left(), registry, scope, source)?;
|
||||
let right = evaluate_baseline_expr(binary.right(), registry, scope, source)?;
|
||||
|
||||
@ -48,7 +48,7 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
)),
|
||||
}
|
||||
}
|
||||
RawExpression::Range(range) => {
|
||||
Expression::Range(range) => {
|
||||
let left = range.left();
|
||||
let right = range.right();
|
||||
|
||||
@ -68,7 +68,7 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
|
||||
Ok(UntaggedValue::range(left, right).into_value(tag))
|
||||
}
|
||||
RawExpression::List(list) => {
|
||||
Expression::List(list) => {
|
||||
let mut exprs = vec![];
|
||||
|
||||
for expr in list {
|
||||
@ -78,13 +78,13 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
|
||||
Ok(UntaggedValue::Table(exprs).into_value(tag))
|
||||
}
|
||||
RawExpression::Block(block) => Ok(UntaggedValue::Block(Evaluate::new(Block::new(
|
||||
Expression::Block(block) => Ok(UntaggedValue::Block(Evaluate::new(Block::new(
|
||||
block.clone(),
|
||||
source.clone(),
|
||||
tag.clone(),
|
||||
)))
|
||||
.into_value(&tag)),
|
||||
RawExpression::Path(path) => {
|
||||
Expression::Path(path) => {
|
||||
let value = evaluate_baseline_expr(path.head(), registry, scope, source)?;
|
||||
let mut item = value;
|
||||
|
||||
@ -122,37 +122,29 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
|
||||
Ok(item.value.into_value(tag))
|
||||
}
|
||||
RawExpression::Boolean(_boolean) => unimplemented!(),
|
||||
Expression::Boolean(_boolean) => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_literal(literal: &hir::Literal, source: &Text) -> Value {
|
||||
match &literal.literal {
|
||||
hir::RawLiteral::ColumnPath(path) => {
|
||||
fn evaluate_literal(literal: &hir::Literal, span: Span, source: &Text) -> Value {
|
||||
match &literal {
|
||||
hir::Literal::ColumnPath(path) => {
|
||||
let members = path
|
||||
.iter()
|
||||
.map(|member| member.to_path_member(source))
|
||||
.collect();
|
||||
|
||||
UntaggedValue::Primitive(Primitive::ColumnPath(ColumnPath::new(members)))
|
||||
.into_value(&literal.span)
|
||||
.into_value(span)
|
||||
}
|
||||
hir::RawLiteral::Number(int) => match int {
|
||||
nu_parser::Number::Int(i) => UntaggedValue::int(i.clone()).into_value(literal.span),
|
||||
nu_parser::Number::Decimal(d) => {
|
||||
UntaggedValue::decimal(d.clone()).into_value(literal.span)
|
||||
}
|
||||
hir::Literal::Number(int) => match int {
|
||||
nu_parser::Number::Int(i) => UntaggedValue::int(i.clone()).into_value(span),
|
||||
nu_parser::Number::Decimal(d) => UntaggedValue::decimal(d.clone()).into_value(span),
|
||||
},
|
||||
hir::RawLiteral::Size(int, unit) => unit.compute(&int).into_value(literal.span),
|
||||
hir::RawLiteral::String(tag) => {
|
||||
UntaggedValue::string(tag.slice(source)).into_value(literal.span)
|
||||
}
|
||||
hir::RawLiteral::GlobPattern(pattern) => {
|
||||
UntaggedValue::pattern(pattern).into_value(literal.span)
|
||||
}
|
||||
hir::RawLiteral::Bare => {
|
||||
UntaggedValue::string(literal.span.slice(source)).into_value(literal.span)
|
||||
}
|
||||
hir::Literal::Size(int, unit) => unit.compute(&int).into_value(span),
|
||||
hir::Literal::String(tag) => UntaggedValue::string(tag.slice(source)).into_value(span),
|
||||
hir::Literal::GlobPattern(pattern) => UntaggedValue::pattern(pattern).into_value(span),
|
||||
hir::Literal::Bare => UntaggedValue::string(span.slice(source)).into_value(span),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ macro_rules! trace_out_stream {
|
||||
}
|
||||
|
||||
pub(crate) use nu_protocol::{errln, outln};
|
||||
use nu_source::HasFallibleSpan;
|
||||
|
||||
pub(crate) use crate::commands::command::{
|
||||
CallInfoExt, CommandArgs, PerItemCommand, RawCommandArgs, RunnableContext,
|
||||
@ -131,12 +132,12 @@ where
|
||||
fn to_input_stream(self) -> InputStream {
|
||||
InputStream {
|
||||
values: self
|
||||
.map(|item| {
|
||||
if let Ok(result) = item.into() {
|
||||
result
|
||||
} else {
|
||||
unreachable!("Internal errors: to_input_stream in inconsistent state")
|
||||
}
|
||||
.map(|item| match item.into() {
|
||||
Ok(result) => result,
|
||||
Err(err) => match HasFallibleSpan::maybe_span(&err) {
|
||||
Some(span) => nu_protocol::UntaggedValue::Error(err).into_value(span),
|
||||
None => nu_protocol::UntaggedValue::Error(err).into_untagged_value(),
|
||||
},
|
||||
})
|
||||
.boxed(),
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
use crate::context::CommandRegistry;
|
||||
|
||||
use derive_new::new;
|
||||
use nu_parser::ExpandContext;
|
||||
use nu_source::{HasSpan, Text};
|
||||
use rustyline::completion::{Completer, FilenameCompleter};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(new)]
|
||||
pub(crate) struct NuCompleter {
|
||||
pub file_completer: FilenameCompleter,
|
||||
pub commands: CommandRegistry,
|
||||
pub homedir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl NuCompleter {
|
||||
@ -17,7 +20,15 @@ impl NuCompleter {
|
||||
pos: usize,
|
||||
context: &rustyline::Context,
|
||||
) -> rustyline::Result<(usize, Vec<rustyline::completion::Pair>)> {
|
||||
let commands: Vec<String> = self.commands.names().unwrap_or_else(|_| vec![]);
|
||||
let text = Text::from(line);
|
||||
let expand_context =
|
||||
ExpandContext::new(Box::new(self.commands.clone()), &text, self.homedir.clone());
|
||||
|
||||
#[allow(unused)]
|
||||
// smarter completions
|
||||
let shapes = nu_parser::pipeline_shapes(line, expand_context);
|
||||
|
||||
let commands: Vec<String> = self.commands.names();
|
||||
|
||||
let line_chars: Vec<_> = line[..pos].chars().collect();
|
||||
|
||||
@ -100,8 +111,6 @@ impl NuCompleter {
|
||||
if let Ok(val) = nu_parser::parse(&line_copy) {
|
||||
let source = Text::from(line);
|
||||
let pipeline_list = vec![val.clone()];
|
||||
let mut iterator =
|
||||
nu_parser::TokensIterator::all(&pipeline_list, source.clone(), val.span());
|
||||
|
||||
let expand_context = nu_parser::ExpandContext {
|
||||
homedir: None,
|
||||
@ -109,10 +118,12 @@ impl NuCompleter {
|
||||
source: &source,
|
||||
};
|
||||
|
||||
let result =
|
||||
nu_parser::expand_syntax(&nu_parser::PipelineShape, &mut iterator, &expand_context);
|
||||
let mut iterator =
|
||||
nu_parser::TokensIterator::new(&pipeline_list, expand_context, val.span());
|
||||
|
||||
if let Ok(result) = result {
|
||||
let result = iterator.expand_infallible(nu_parser::PipelineShape);
|
||||
|
||||
if result.failed.is_none() {
|
||||
for command in result.commands.list {
|
||||
if let nu_parser::ClassifiedCommand::Internal(nu_parser::InternalCommand {
|
||||
args,
|
||||
|
@ -10,6 +10,7 @@ use crate::shell::completer::NuCompleter;
|
||||
use crate::shell::shell::Shell;
|
||||
use crate::utils::FileStructure;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ExpandContext;
|
||||
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue};
|
||||
use rustyline::completion::FilenameCompleter;
|
||||
use rustyline::hint::{Hinter, HistoryHinter};
|
||||
@ -38,6 +39,7 @@ impl Clone for FilesystemShell {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands: self.completer.commands.clone(),
|
||||
homedir: self.homedir(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
}
|
||||
@ -54,6 +56,7 @@ impl FilesystemShell {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands,
|
||||
homedir: dirs::home_dir(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
})
|
||||
@ -67,6 +70,7 @@ impl FilesystemShell {
|
||||
completer: NuCompleter {
|
||||
file_completer: FilenameCompleter::new(),
|
||||
commands,
|
||||
homedir: dirs::home_dir(),
|
||||
},
|
||||
hinter: HistoryHinter {},
|
||||
}
|
||||
@ -1131,7 +1135,13 @@ impl Shell for FilesystemShell {
|
||||
self.completer.complete(line, pos, ctx)
|
||||
}
|
||||
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
fn hint(
|
||||
&self,
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
_expand_context: ExpandContext,
|
||||
) -> Option<String> {
|
||||
self.hinter.hint(line, pos, ctx)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use crate::data::command_dict;
|
||||
use crate::prelude::*;
|
||||
use crate::shell::shell::Shell;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ExpandContext;
|
||||
use nu_protocol::{
|
||||
Primitive, ReturnSuccess, ShellTypeName, TaggedDictBuilder, UntaggedValue, Value,
|
||||
};
|
||||
@ -25,25 +26,28 @@ impl HelpShell {
|
||||
let mut cmds = TaggedDictBuilder::new(Tag::unknown());
|
||||
let mut specs = Vec::new();
|
||||
|
||||
let snapshot = registry.snapshot()?;
|
||||
for cmd in registry.names() {
|
||||
if let Some(cmd_value) = registry.get_command(&cmd) {
|
||||
let mut spec = TaggedDictBuilder::new(Tag::unknown());
|
||||
let value = command_dict(cmd_value, Tag::unknown());
|
||||
|
||||
for (name, cmd) in snapshot.iter() {
|
||||
let mut spec = TaggedDictBuilder::new(Tag::unknown());
|
||||
let value = command_dict(cmd.clone(), Tag::unknown());
|
||||
spec.insert_untagged("name", cmd);
|
||||
spec.insert_untagged(
|
||||
"description",
|
||||
value
|
||||
.get_data_by_key("usage".spanned_unknown())
|
||||
.ok_or_else(|| {
|
||||
ShellError::untagged_runtime_error(
|
||||
"Internal error: expected to find usage",
|
||||
)
|
||||
})?
|
||||
.as_string()?,
|
||||
);
|
||||
spec.insert_value("details", value);
|
||||
|
||||
spec.insert_untagged("name", name.to_string());
|
||||
spec.insert_untagged(
|
||||
"description",
|
||||
value
|
||||
.get_data_by_key("usage".spanned_unknown())
|
||||
.ok_or_else(|| {
|
||||
ShellError::untagged_runtime_error("Internal error: expected to find usage")
|
||||
})?
|
||||
.as_string()?,
|
||||
);
|
||||
spec.insert_value("details", value);
|
||||
|
||||
specs.push(spec.into_value());
|
||||
specs.push(spec.into_value());
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
cmds.insert_untagged("help", UntaggedValue::Table(specs));
|
||||
@ -240,7 +244,13 @@ impl Shell for HelpShell {
|
||||
Ok((replace_pos, completions))
|
||||
}
|
||||
|
||||
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
fn hint(
|
||||
&self,
|
||||
_line: &str,
|
||||
_pos: usize,
|
||||
_ctx: &rustyline::Context<'_>,
|
||||
_context: ExpandContext,
|
||||
) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use crate::context::Context;
|
||||
use ansi_term::Color;
|
||||
use log::{log_enabled, trace};
|
||||
use nu_parser::hir::syntax_shape::color_fallible_syntax;
|
||||
use nu_parser::{FlatShape, PipelineShape, TokenNode, TokensIterator};
|
||||
use nu_protocol::outln;
|
||||
use nu_source::{nom_input, HasSpan, Spanned, Tag, Tagged, Text};
|
||||
use ansi_term::{Color, Style};
|
||||
use log::log_enabled;
|
||||
use nu_parser::{FlatShape, PipelineShape, ShapeResult, Token, TokensIterator};
|
||||
use nu_protocol::{errln, outln};
|
||||
use nu_source::{nom_input, HasSpan, Tag, Tagged, Text};
|
||||
use rustyline::completion::Completer;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::highlight::Highlighter;
|
||||
@ -39,10 +38,10 @@ impl Completer for Helper {
|
||||
|
||||
impl Hinter for Helper {
|
||||
fn hint(&self, line: &str, pos: usize, ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
match self.context.shell_manager.hint(line, pos, ctx) {
|
||||
Ok(output) => output,
|
||||
Err(e) => Some(format!("{}", e)),
|
||||
}
|
||||
let text = Text::from(line);
|
||||
self.context
|
||||
.shell_manager
|
||||
.hint(line, pos, ctx, self.context.expand_context(&text))
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,53 +70,47 @@ impl Highlighter for Helper {
|
||||
match tokens {
|
||||
Err(_) => Cow::Borrowed(line),
|
||||
Ok((_rest, v)) => {
|
||||
let mut out = String::new();
|
||||
let pipeline = match v.as_pipeline() {
|
||||
Err(_) => return Cow::Borrowed(line),
|
||||
Ok(v) => v,
|
||||
};
|
||||
|
||||
let tokens = vec![TokenNode::Pipeline(pipeline)];
|
||||
let mut tokens = TokensIterator::all(&tokens[..], Text::from(line), v.span());
|
||||
|
||||
let text = Text::from(line);
|
||||
match self.context.expand_context(&text) {
|
||||
Ok(expand_context) => {
|
||||
let shapes = {
|
||||
// We just constructed a token list that only contains a pipeline, so it can't fail
|
||||
if let Err(err) =
|
||||
color_fallible_syntax(&PipelineShape, &mut tokens, &expand_context)
|
||||
{
|
||||
let error_msg = format!("{}", err);
|
||||
return Cow::Owned(error_msg);
|
||||
}
|
||||
tokens.with_color_tracer(|_, tracer| tracer.finish());
|
||||
let expand_context = self.context.expand_context(&text);
|
||||
|
||||
tokens.state().shapes()
|
||||
};
|
||||
let tokens = vec![Token::Pipeline(pipeline).into_spanned(v.span())];
|
||||
let mut tokens = TokensIterator::new(&tokens[..], expand_context, v.span());
|
||||
|
||||
trace!(target: "nu::color_syntax", "{:#?}", tokens.color_tracer());
|
||||
let shapes = {
|
||||
// We just constructed a token list that only contains a pipeline, so it can't fail
|
||||
let result = tokens.expand_infallible(PipelineShape);
|
||||
|
||||
if log_enabled!(target: "nu::color_syntax", log::Level::Debug) {
|
||||
outln!("");
|
||||
let _ = ptree::print_tree(
|
||||
&tokens.color_tracer().clone().print(Text::from(line)),
|
||||
);
|
||||
outln!("");
|
||||
}
|
||||
|
||||
for shape in shapes {
|
||||
let styled = paint_flat_shape(&shape, line);
|
||||
out.push_str(&styled);
|
||||
}
|
||||
|
||||
Cow::Owned(out)
|
||||
}
|
||||
Err(err) => {
|
||||
let error_msg = format!("{}", err);
|
||||
Cow::Owned(error_msg)
|
||||
if let Some(failure) = result.failed {
|
||||
errln!(
|
||||
"BUG: PipelineShape didn't find a pipeline :: {:#?}",
|
||||
failure
|
||||
);
|
||||
}
|
||||
|
||||
tokens.finish_tracer();
|
||||
|
||||
tokens.state().shapes()
|
||||
};
|
||||
|
||||
if log_enabled!(target: "nu::expand_syntax", log::Level::Debug) {
|
||||
outln!("");
|
||||
let _ =
|
||||
ptree::print_tree(&tokens.expand_tracer().clone().print(Text::from(line)));
|
||||
outln!("");
|
||||
}
|
||||
|
||||
let mut painter = Painter::new();
|
||||
|
||||
for shape in shapes {
|
||||
painter.paint_shape(&shape, line);
|
||||
}
|
||||
|
||||
Cow::Owned(painter.into_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,45 +132,75 @@ fn vec_tag<T>(input: Vec<Tagged<T>>) -> Option<Tag> {
|
||||
})
|
||||
}
|
||||
|
||||
fn paint_flat_shape(flat_shape: &Spanned<FlatShape>, line: &str) -> String {
|
||||
let style = match &flat_shape.item {
|
||||
FlatShape::OpenDelimiter(_) => Color::White.normal(),
|
||||
FlatShape::CloseDelimiter(_) => Color::White.normal(),
|
||||
FlatShape::ItVariable => Color::Purple.bold(),
|
||||
FlatShape::Variable => Color::Purple.normal(),
|
||||
FlatShape::CompareOperator => Color::Yellow.normal(),
|
||||
FlatShape::DotDot => Color::Yellow.bold(),
|
||||
FlatShape::Dot => Color::White.normal(),
|
||||
FlatShape::InternalCommand => Color::Cyan.bold(),
|
||||
FlatShape::ExternalCommand => Color::Cyan.normal(),
|
||||
FlatShape::ExternalWord => Color::Green.bold(),
|
||||
FlatShape::BareMember => Color::Yellow.bold(),
|
||||
FlatShape::StringMember => Color::Yellow.bold(),
|
||||
FlatShape::String => Color::Green.normal(),
|
||||
FlatShape::Path => Color::Cyan.normal(),
|
||||
FlatShape::GlobPattern => Color::Cyan.bold(),
|
||||
FlatShape::Word => Color::Green.normal(),
|
||||
FlatShape::Pipe => Color::Purple.bold(),
|
||||
FlatShape::Flag => Color::Blue.bold(),
|
||||
FlatShape::ShorthandFlag => Color::Blue.bold(),
|
||||
FlatShape::Int => Color::Purple.bold(),
|
||||
FlatShape::Decimal => Color::Purple.bold(),
|
||||
FlatShape::Whitespace | FlatShape::Separator => Color::White.normal(),
|
||||
FlatShape::Comment => Color::Green.bold(),
|
||||
FlatShape::Error => Color::Red.bold(),
|
||||
FlatShape::Size { number, unit } => {
|
||||
let number = number.slice(line);
|
||||
let unit = unit.slice(line);
|
||||
return format!(
|
||||
"{}{}",
|
||||
Color::Purple.bold().paint(number),
|
||||
Color::Cyan.bold().paint(unit)
|
||||
);
|
||||
}
|
||||
};
|
||||
struct Painter {
|
||||
current: Style,
|
||||
buffer: String,
|
||||
}
|
||||
|
||||
let body = flat_shape.span.slice(line);
|
||||
style.paint(body).to_string()
|
||||
impl Painter {
|
||||
fn new() -> Painter {
|
||||
Painter {
|
||||
current: Style::default(),
|
||||
buffer: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_string(self) -> String {
|
||||
self.buffer
|
||||
}
|
||||
|
||||
fn paint_shape(&mut self, shape: &ShapeResult, line: &str) {
|
||||
let style = match &shape {
|
||||
ShapeResult::Success(shape) => match shape.item {
|
||||
FlatShape::OpenDelimiter(_) => Color::White.normal(),
|
||||
FlatShape::CloseDelimiter(_) => Color::White.normal(),
|
||||
FlatShape::ItVariable | FlatShape::Keyword => Color::Purple.bold(),
|
||||
FlatShape::Variable | FlatShape::Identifier => Color::Purple.normal(),
|
||||
FlatShape::Type => Color::Blue.bold(),
|
||||
FlatShape::CompareOperator => Color::Yellow.normal(),
|
||||
FlatShape::DotDot => Color::Yellow.bold(),
|
||||
FlatShape::Dot => Style::new().fg(Color::White).on(Color::Black),
|
||||
FlatShape::InternalCommand => Color::Cyan.bold(),
|
||||
FlatShape::ExternalCommand => Color::Cyan.normal(),
|
||||
FlatShape::ExternalWord => Color::Green.bold(),
|
||||
FlatShape::BareMember => Color::Yellow.bold(),
|
||||
FlatShape::StringMember => Color::Yellow.bold(),
|
||||
FlatShape::String => Color::Green.normal(),
|
||||
FlatShape::Path => Color::Cyan.normal(),
|
||||
FlatShape::GlobPattern => Color::Cyan.bold(),
|
||||
FlatShape::Word => Color::Green.normal(),
|
||||
FlatShape::Pipe => Color::Purple.bold(),
|
||||
FlatShape::Flag => Color::Blue.bold(),
|
||||
FlatShape::ShorthandFlag => Color::Blue.bold(),
|
||||
FlatShape::Int => Color::Purple.bold(),
|
||||
FlatShape::Decimal => Color::Purple.bold(),
|
||||
FlatShape::Whitespace | FlatShape::Separator => Color::White.normal(),
|
||||
FlatShape::Comment => Color::Green.bold(),
|
||||
FlatShape::Garbage => Style::new().fg(Color::White).on(Color::Red),
|
||||
FlatShape::Size { number, unit } => {
|
||||
let number = number.slice(line);
|
||||
let unit = unit.slice(line);
|
||||
|
||||
self.paint(Color::Purple.bold(), number);
|
||||
self.paint(Color::Cyan.bold(), unit);
|
||||
return;
|
||||
}
|
||||
},
|
||||
ShapeResult::Fallback { shape, .. } => match shape.item {
|
||||
FlatShape::Whitespace | FlatShape::Separator => Color::White.normal(),
|
||||
_ => Style::new().fg(Color::White).on(Color::Red),
|
||||
},
|
||||
};
|
||||
|
||||
self.paint(style, shape.span().slice(line));
|
||||
}
|
||||
|
||||
fn paint(&mut self, style: Style, body: &str) {
|
||||
let infix = self.current.infix(style);
|
||||
self.current = style;
|
||||
self.buffer
|
||||
.push_str(&format!("{}{}", infix, style.paint(body)));
|
||||
}
|
||||
}
|
||||
|
||||
impl rustyline::Helper for Helper {}
|
||||
|
@ -7,6 +7,7 @@ use crate::commands::rm::RemoveArgs;
|
||||
use crate::prelude::*;
|
||||
use crate::stream::OutputStream;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ExpandContext;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub trait Shell: std::fmt::Debug {
|
||||
@ -34,5 +35,11 @@ pub trait Shell: std::fmt::Debug {
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError>;
|
||||
|
||||
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String>;
|
||||
fn hint(
|
||||
&self,
|
||||
_line: &str,
|
||||
_pos: usize,
|
||||
_ctx: &rustyline::Context<'_>,
|
||||
_context: ExpandContext,
|
||||
) -> Option<String>;
|
||||
}
|
||||
|
@ -9,10 +9,12 @@ use crate::shell::filesystem_shell::FilesystemShell;
|
||||
use crate::shell::shell::Shell;
|
||||
use crate::stream::OutputStream;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ExpandContext;
|
||||
use parking_lot::Mutex;
|
||||
use std::error::Error;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ShellManager {
|
||||
@ -30,95 +32,53 @@ impl ShellManager {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn insert_at_current(&mut self, shell: Box<dyn Shell + Send>) -> Result<(), ShellError> {
|
||||
if let Ok(mut shells) = self.shells.lock() {
|
||||
shells.push(shell);
|
||||
} else {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer",
|
||||
));
|
||||
}
|
||||
|
||||
let shells_len = if let Ok(shells) = self.shells.lock() {
|
||||
shells.len()
|
||||
} else {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer",
|
||||
));
|
||||
};
|
||||
|
||||
self.current_shell.store(shells_len - 1, Ordering::SeqCst);
|
||||
self.set_path(self.path()?)
|
||||
pub fn insert_at_current(&mut self, shell: Box<dyn Shell + Send>) {
|
||||
self.shells.lock().push(shell);
|
||||
self.current_shell
|
||||
.store(self.shells.lock().len() - 1, Ordering::SeqCst);
|
||||
self.set_path(self.path());
|
||||
}
|
||||
|
||||
pub fn current_shell(&self) -> usize {
|
||||
self.current_shell.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn remove_at_current(&mut self) -> Result<(), ShellError> {
|
||||
pub fn remove_at_current(&mut self) {
|
||||
{
|
||||
if let Ok(mut shells) = self.shells.lock() {
|
||||
if shells.len() > 0 {
|
||||
if self.current_shell() == shells.len() - 1 {
|
||||
shells.pop();
|
||||
let new_len = shells.len();
|
||||
if new_len > 0 {
|
||||
self.current_shell.store(new_len - 1, Ordering::SeqCst);
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
let mut shells = self.shells.lock();
|
||||
if shells.len() > 0 {
|
||||
if self.current_shell() == shells.len() - 1 {
|
||||
shells.pop();
|
||||
let new_len = shells.len();
|
||||
if new_len > 0 {
|
||||
self.current_shell.store(new_len - 1, Ordering::SeqCst);
|
||||
} else {
|
||||
shells.remove(self.current_shell());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
shells.remove(self.current_shell());
|
||||
}
|
||||
} else {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer",
|
||||
));
|
||||
}
|
||||
}
|
||||
self.set_path(self.path()?)
|
||||
self.set_path(self.path())
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> Result<bool, ShellError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
Ok(shells.is_empty())
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (is_empty)",
|
||||
))
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.shells.lock().is_empty()
|
||||
}
|
||||
|
||||
pub fn path(&self) -> Result<String, ShellError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
Ok(shells[self.current_shell()].path())
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (path)",
|
||||
))
|
||||
}
|
||||
pub fn path(&self) -> String {
|
||||
self.shells.lock()[self.current_shell()].path()
|
||||
}
|
||||
|
||||
pub fn pwd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
shells[self.current_shell()].pwd(args)
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (pwd)",
|
||||
))
|
||||
}
|
||||
let env = self.shells.lock();
|
||||
|
||||
env[self.current_shell()].pwd(args)
|
||||
}
|
||||
|
||||
pub fn set_path(&mut self, path: String) -> Result<(), ShellError> {
|
||||
if let Ok(mut shells) = self.shells.lock() {
|
||||
shells[self.current_shell()].set_path(path);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (set_path)",
|
||||
))
|
||||
}
|
||||
pub fn set_path(&mut self, path: String) {
|
||||
self.shells.lock()[self.current_shell()].set_path(path)
|
||||
}
|
||||
|
||||
pub fn complete(
|
||||
@ -127,14 +87,7 @@ impl ShellManager {
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<(usize, Vec<rustyline::completion::Pair>), rustyline::error::ReadlineError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
shells[self.current_shell()].complete(line, pos, ctx)
|
||||
} else {
|
||||
Err(rustyline::error::ReadlineError::Io(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"Internal error: could not lock shells ring buffer (complete)",
|
||||
)))
|
||||
}
|
||||
self.shells.lock()[self.current_shell()].complete(line, pos, ctx)
|
||||
}
|
||||
|
||||
pub fn hint(
|
||||
@ -142,62 +95,41 @@ impl ShellManager {
|
||||
line: &str,
|
||||
pos: usize,
|
||||
ctx: &rustyline::Context<'_>,
|
||||
) -> Result<Option<String>, ShellError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
Ok(shells[self.current_shell()].hint(line, pos, ctx))
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (hint)",
|
||||
))
|
||||
}
|
||||
context: ExpandContext,
|
||||
) -> Option<String> {
|
||||
self.shells.lock()[self.current_shell()].hint(line, pos, ctx, context)
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> Result<(), ShellError> {
|
||||
pub fn next(&mut self) {
|
||||
{
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
let shell_len = shells.len();
|
||||
if self.current_shell() == (shell_len - 1) {
|
||||
self.current_shell.store(0, Ordering::SeqCst);
|
||||
} else {
|
||||
self.current_shell
|
||||
.store(self.current_shell() + 1, Ordering::SeqCst);
|
||||
}
|
||||
let shell_len = self.shells.lock().len();
|
||||
if self.current_shell() == (shell_len - 1) {
|
||||
self.current_shell.store(0, Ordering::SeqCst);
|
||||
} else {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (next)",
|
||||
));
|
||||
self.current_shell
|
||||
.store(self.current_shell() + 1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
self.set_path(self.path()?)
|
||||
self.set_path(self.path())
|
||||
}
|
||||
|
||||
pub fn prev(&mut self) -> Result<(), ShellError> {
|
||||
pub fn prev(&mut self) {
|
||||
{
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
let shell_len = shells.len();
|
||||
if self.current_shell() == 0 {
|
||||
self.current_shell.store(shell_len - 1, Ordering::SeqCst);
|
||||
} else {
|
||||
self.current_shell
|
||||
.store(self.current_shell() - 1, Ordering::SeqCst);
|
||||
}
|
||||
let shell_len = self.shells.lock().len();
|
||||
if self.current_shell() == 0 {
|
||||
self.current_shell.store(shell_len - 1, Ordering::SeqCst);
|
||||
} else {
|
||||
return Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (prev)",
|
||||
));
|
||||
self.current_shell
|
||||
.store(self.current_shell() - 1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
self.set_path(self.path()?)
|
||||
self.set_path(self.path())
|
||||
}
|
||||
|
||||
pub fn homedir(&self) -> Result<Option<PathBuf>, ShellError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
Ok(shells[self.current_shell()].homedir())
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (homedir)",
|
||||
))
|
||||
}
|
||||
pub fn homedir(&self) -> Option<PathBuf> {
|
||||
let env = self.shells.lock();
|
||||
|
||||
env[self.current_shell()].homedir()
|
||||
}
|
||||
|
||||
pub fn ls(
|
||||
@ -205,23 +137,15 @@ impl ShellManager {
|
||||
args: LsArgs,
|
||||
context: &RunnablePerItemContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
shells[self.current_shell()].ls(args, context)
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (ls)",
|
||||
))
|
||||
}
|
||||
let env = self.shells.lock();
|
||||
|
||||
env[self.current_shell()].ls(args, context)
|
||||
}
|
||||
|
||||
pub fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result<OutputStream, ShellError> {
|
||||
if let Ok(shells) = self.shells.lock() {
|
||||
shells[self.current_shell()].cd(args)
|
||||
} else {
|
||||
Err(ShellError::untagged_runtime_error(
|
||||
"Internal error: could not lock shells ring buffer (cd)",
|
||||
))
|
||||
}
|
||||
let env = self.shells.lock();
|
||||
|
||||
env[self.current_shell()].cd(args)
|
||||
}
|
||||
|
||||
pub fn cp(
|
||||
@ -231,17 +155,8 @@ impl ShellManager {
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
match shells {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].cp(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
let path = shells[self.current_shell()].path();
|
||||
shells[self.current_shell()].cp(args, context.name.clone(), &path)
|
||||
}
|
||||
|
||||
pub fn rm(
|
||||
@ -251,17 +166,8 @@ impl ShellManager {
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
match shells {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].rm(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
let path = shells[self.current_shell()].path();
|
||||
shells[self.current_shell()].rm(args, context.name.clone(), &path)
|
||||
}
|
||||
|
||||
pub fn mkdir(
|
||||
@ -271,17 +177,8 @@ impl ShellManager {
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
match shells {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].mkdir(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
let path = shells[self.current_shell()].path();
|
||||
shells[self.current_shell()].mkdir(args, context.name.clone(), &path)
|
||||
}
|
||||
|
||||
pub fn mv(
|
||||
@ -291,16 +188,7 @@ impl ShellManager {
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
let shells = self.shells.lock();
|
||||
|
||||
match shells {
|
||||
Ok(x) => {
|
||||
let path = x[self.current_shell()].path();
|
||||
x[self.current_shell()].mv(args, context.name.clone(), &path)
|
||||
}
|
||||
Err(e) => Err(ShellError::labeled_error(
|
||||
format!("Internal error: could not lock {}", e),
|
||||
"Internal error: could not lock",
|
||||
&context.name,
|
||||
)),
|
||||
}
|
||||
let path = shells[self.current_shell()].path();
|
||||
shells[self.current_shell()].mv(args, context.name.clone(), &path)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use crate::prelude::*;
|
||||
use crate::shell::shell::Shell;
|
||||
use crate::utils::ValueStructure;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::ExpandContext;
|
||||
use nu_protocol::{ReturnSuccess, ShellTypeName, UntaggedValue, Value};
|
||||
use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -280,7 +281,13 @@ impl Shell for ValueShell {
|
||||
Ok((replace_pos, completions))
|
||||
}
|
||||
|
||||
fn hint(&self, _line: &str, _pos: usize, _ctx: &rustyline::Context<'_>) -> Option<String> {
|
||||
fn hint(
|
||||
&self,
|
||||
_line: &str,
|
||||
_pos: usize,
|
||||
_ctx: &rustyline::Context<'_>,
|
||||
_context: ExpandContext,
|
||||
) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user