mirror of
https://github.com/nushell/nushell
synced 2024-11-14 17:07:07 +00:00
More ununwraps (#1152)
* More ununwraps * More ununwraps * Update completer.rs * Update completer.rs
This commit is contained in:
parent
3e3cb15f3d
commit
339a2de0eb
17 changed files with 186 additions and 100 deletions
16
src/cli.rs
16
src/cli.rs
|
@ -61,16 +61,16 @@ fn load_plugin(path: &std::path::Path, context: &mut Context) -> Result<(), Shel
|
||||||
let name = params.name.clone();
|
let name = params.name.clone();
|
||||||
let fname = fname.to_string();
|
let fname = fname.to_string();
|
||||||
|
|
||||||
if context.get_command(&name).is_some() {
|
if context.get_command(&name)?.is_some() {
|
||||||
trace!("plugin {:?} already loaded.", &name);
|
trace!("plugin {:?} already loaded.", &name);
|
||||||
} else if params.is_filter {
|
} else if params.is_filter {
|
||||||
context.add_commands(vec![whole_stream_command(PluginCommand::new(
|
context.add_commands(vec![whole_stream_command(
|
||||||
name, fname, params,
|
PluginCommand::new(name, fname, params),
|
||||||
))]);
|
)])?;
|
||||||
} else {
|
} else {
|
||||||
context.add_commands(vec![whole_stream_command(PluginSink::new(
|
context.add_commands(vec![whole_stream_command(PluginSink::new(
|
||||||
name, fname, params,
|
name, fname, params,
|
||||||
))]);
|
))])?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -328,7 +328,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
whole_stream_command(FromXML),
|
whole_stream_command(FromXML),
|
||||||
whole_stream_command(FromYAML),
|
whole_stream_command(FromYAML),
|
||||||
whole_stream_command(FromYML),
|
whole_stream_command(FromYML),
|
||||||
]);
|
])?;
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(data_processing_primitives)] {
|
if #[cfg(data_processing_primitives)] {
|
||||||
|
@ -337,7 +337,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
whole_stream_command(EvaluateBy),
|
whole_stream_command(EvaluateBy),
|
||||||
whole_stream_command(TSortBy),
|
whole_stream_command(TSortBy),
|
||||||
whole_stream_command(MapMaxBy),
|
whole_stream_command(MapMaxBy),
|
||||||
]);
|
])?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
||||||
{
|
{
|
||||||
context.add_commands(vec![whole_stream_command(
|
context.add_commands(vec![whole_stream_command(
|
||||||
crate::commands::clip::clipboard::Clip,
|
crate::commands::clip::clipboard::Clip,
|
||||||
)]);
|
)])?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 new_output_stream: OutputStream = stream.to_output_stream();
|
||||||
let mut finished = false;
|
let mut finished = false;
|
||||||
let mut current_idx = 0;
|
let mut current_idx = 0;
|
||||||
|
@ -136,7 +136,7 @@ pub fn autoview(
|
||||||
value: UntaggedValue::Primitive(Primitive::String(ref s)),
|
value: UntaggedValue::Primitive(Primitive::String(ref s)),
|
||||||
tag: Tag { anchor, span },
|
tag: Tag { anchor, span },
|
||||||
} if anchor.is_some() => {
|
} if anchor.is_some() => {
|
||||||
if let Some(text) = text {
|
if let Some(text) = text? {
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span }));
|
stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span }));
|
||||||
let result = text.run(raw.with_input(stream.into()), &context.commands);
|
let result = text.run(raw.with_input(stream.into()), &context.commands);
|
||||||
|
@ -155,7 +155,7 @@ pub fn autoview(
|
||||||
value: UntaggedValue::Primitive(Primitive::Line(ref s)),
|
value: UntaggedValue::Primitive(Primitive::Line(ref s)),
|
||||||
tag: Tag { anchor, span },
|
tag: Tag { anchor, span },
|
||||||
} if anchor.is_some() => {
|
} if anchor.is_some() => {
|
||||||
if let Some(text) = text {
|
if let Some(text) = text? {
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span }));
|
stream.push_back(UntaggedValue::string(s).into_value(Tag { anchor, span }));
|
||||||
let result = text.run(raw.with_input(stream.into()), &context.commands);
|
let result = text.run(raw.with_input(stream.into()), &context.commands);
|
||||||
|
@ -190,7 +190,7 @@ pub fn autoview(
|
||||||
}
|
}
|
||||||
|
|
||||||
Value { value: UntaggedValue::Primitive(Primitive::Binary(ref b)), .. } => {
|
Value { value: UntaggedValue::Primitive(Primitive::Binary(ref b)), .. } => {
|
||||||
if let Some(binary) = binary {
|
if let Some(binary) = binary? {
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
stream.push_back(x);
|
stream.push_back(x);
|
||||||
let result = binary.run(raw.with_input(stream.into()), &context.commands);
|
let result = binary.run(raw.with_input(stream.into()), &context.commands);
|
||||||
|
@ -205,7 +205,7 @@ pub fn autoview(
|
||||||
yield Err(e);
|
yield Err(e);
|
||||||
}
|
}
|
||||||
Value { value: ref item, .. } => {
|
Value { value: ref item, .. } => {
|
||||||
if let Some(table) = table {
|
if let Some(table) = table? {
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
stream.push_back(x);
|
stream.push_back(x);
|
||||||
let result = table.run(raw.with_input(stream.into()), &context.commands);
|
let result = table.run(raw.with_input(stream.into()), &context.commands);
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub(crate) async fn run_internal_command(
|
||||||
let contents_tag = tagged_contents.tag.clone();
|
let contents_tag = tagged_contents.tag.clone();
|
||||||
let command_name = format!("from-{}", extension);
|
let command_name = format!("from-{}", extension);
|
||||||
let command = command.clone();
|
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 {
|
let new_args = RawCommandArgs {
|
||||||
host: context.host.clone(),
|
host: context.host.clone(),
|
||||||
ctrl_c: context.ctrl_c.clone(),
|
ctrl_c: context.ctrl_c.clone(),
|
||||||
|
@ -103,7 +103,7 @@ pub(crate) async fn run_internal_command(
|
||||||
HelpShell::for_command(
|
HelpShell::for_command(
|
||||||
UntaggedValue::string(cmd).into_value(tag),
|
UntaggedValue::string(cmd).into_value(tag),
|
||||||
&context.registry(),
|
&context.registry(),
|
||||||
).unwrap(),
|
)?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -227,7 +227,7 @@ pub struct RunnableContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunnableContext {
|
impl RunnableContext {
|
||||||
pub fn get_command(&self, name: &str) -> Option<Arc<Command>> {
|
pub fn get_command(&self, name: &str) -> Result<Option<Arc<Command>>, ShellError> {
|
||||||
self.commands.get_command(name)
|
self.commands.get_command(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ impl PerItemCommand for Enter {
|
||||||
|
|
||||||
let (_, command) = (spec[0], spec[1]);
|
let (_, command) = (spec[0], spec[1]);
|
||||||
|
|
||||||
if registry.has(command) {
|
if registry.has(command)? {
|
||||||
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterHelpShell(
|
||||||
UntaggedValue::string(command).into_value(Tag::unknown()),
|
UntaggedValue::string(command).into_value(Tag::unknown()),
|
||||||
)))]
|
)))]
|
||||||
|
@ -88,7 +88,7 @@ impl PerItemCommand for Enter {
|
||||||
if let Some(extension) = file_extension {
|
if let Some(extension) = file_extension {
|
||||||
let command_name = format!("from-{}", extension);
|
let command_name = format!("from-{}", extension);
|
||||||
if let Some(converter) =
|
if let Some(converter) =
|
||||||
registry.get_command(&command_name)
|
registry.get_command(&command_name)?
|
||||||
{
|
{
|
||||||
let new_args = RawCommandArgs {
|
let new_args = RawCommandArgs {
|
||||||
host: raw_args.host,
|
host: raw_args.host,
|
||||||
|
|
|
@ -391,7 +391,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_trims_remaining_separator_space() {
|
fn it_trims_remaining_separator_space() -> Result<(), ShellError> {
|
||||||
let input = r#"
|
let input = r#"
|
||||||
colA colB colC
|
colA colB colC
|
||||||
val1 val2 val3
|
val1 val2 val3
|
||||||
|
@ -399,14 +399,17 @@ mod tests {
|
||||||
|
|
||||||
let trimmed = |s: &str| s.trim() == s;
|
let trimmed = |s: &str| s.trim() == s;
|
||||||
|
|
||||||
let result = string_to_table(input, false, true, 2).unwrap();
|
let result = string_to_table(input, false, true, 2)
|
||||||
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
assert!(result
|
assert!(result
|
||||||
.iter()
|
.iter()
|
||||||
.all(|row| row.iter().all(|(a, b)| trimmed(a) && trimmed(b))))
|
.all(|row| row.iter().all(|(a, b)| trimmed(a) && trimmed(b))));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_keeps_empty_columns() {
|
fn it_keeps_empty_columns() -> Result<(), ShellError> {
|
||||||
let input = r#"
|
let input = r#"
|
||||||
colA col B col C
|
colA col B col C
|
||||||
val2 val3
|
val2 val3
|
||||||
|
@ -414,7 +417,8 @@ mod tests {
|
||||||
val7 val8
|
val7 val8
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = string_to_table(input, false, true, 2).unwrap();
|
let result = string_to_table(input, false, true, 2)
|
||||||
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
vec![
|
vec![
|
||||||
|
@ -434,35 +438,39 @@ mod tests {
|
||||||
owned("col C", "val8")
|
owned("col C", "val8")
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
)
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_uses_the_full_final_column() {
|
fn it_uses_the_full_final_column() -> Result<(), ShellError> {
|
||||||
let input = r#"
|
let input = r#"
|
||||||
colA col B
|
colA col B
|
||||||
val1 val2 trailing value that should be included
|
val1 val2 trailing value that should be included
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = string_to_table(input, false, true, 2).unwrap();
|
let result = string_to_table(input, false, true, 2)
|
||||||
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
vec![vec![
|
vec![vec![
|
||||||
owned("colA", "val1"),
|
owned("colA", "val1"),
|
||||||
owned("col B", "val2 trailing value that should be included"),
|
owned("col B", "val2 trailing value that should be included"),
|
||||||
],]
|
],]
|
||||||
)
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_handles_empty_values_when_headerless_and_aligned_columns() {
|
fn it_handles_empty_values_when_headerless_and_aligned_columns() -> Result<(), ShellError> {
|
||||||
let input = r#"
|
let input = r#"
|
||||||
a multi-word value b d
|
a multi-word value b d
|
||||||
1 3-3 4
|
1 3-3 4
|
||||||
last
|
last
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let result = string_to_table(input, true, true, 2).unwrap();
|
let result = string_to_table(input, true, true, 2)
|
||||||
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
vec![
|
vec![
|
||||||
|
@ -488,22 +496,28 @@ mod tests {
|
||||||
owned("Column5", "last")
|
owned("Column5", "last")
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
)
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn input_is_parsed_correctly_if_either_option_works() {
|
fn input_is_parsed_correctly_if_either_option_works() -> Result<(), ShellError> {
|
||||||
let input = r#"
|
let input = r#"
|
||||||
docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP
|
docker-registry docker-registry=default docker-registry=default 172.30.78.158 5000/TCP
|
||||||
kubernetes component=apiserver,provider=kubernetes <none> 172.30.0.2 443/TCP
|
kubernetes component=apiserver,provider=kubernetes <none> 172.30.0.2 443/TCP
|
||||||
kubernetes-ro component=apiserver,provider=kubernetes <none> 172.30.0.1 80/TCP
|
kubernetes-ro component=apiserver,provider=kubernetes <none> 172.30.0.1 80/TCP
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let aligned_columns_headerless = string_to_table(input, true, true, 2).unwrap();
|
let aligned_columns_headerless = string_to_table(input, true, true, 2)
|
||||||
let separator_headerless = string_to_table(input, true, false, 2).unwrap();
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
let aligned_columns_with_headers = string_to_table(input, false, true, 2).unwrap();
|
let separator_headerless = string_to_table(input, true, false, 2)
|
||||||
let separator_with_headers = string_to_table(input, false, false, 2).unwrap();
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
|
let aligned_columns_with_headers = string_to_table(input, false, true, 2)
|
||||||
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
|
let separator_with_headers = string_to_table(input, false, false, 2)
|
||||||
|
.ok_or_else(|| ShellError::unexpected("table couldn't be parsed"))?;
|
||||||
assert_eq!(aligned_columns_headerless, separator_headerless);
|
assert_eq!(aligned_columns_headerless, separator_headerless);
|
||||||
assert_eq!(aligned_columns_with_headers, separator_with_headers);
|
assert_eq!(aligned_columns_with_headers, separator_with_headers);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,12 @@ impl PerItemCommand for Help {
|
||||||
}) => {
|
}) => {
|
||||||
let mut help = VecDeque::new();
|
let mut help = VecDeque::new();
|
||||||
if document == "commands" {
|
if document == "commands" {
|
||||||
let mut sorted_names = registry.names();
|
let mut sorted_names = registry.names()?;
|
||||||
sorted_names.sort();
|
sorted_names.sort();
|
||||||
for cmd in sorted_names {
|
for cmd in sorted_names {
|
||||||
let mut short_desc = TaggedDictBuilder::new(tag.clone());
|
let mut short_desc = TaggedDictBuilder::new(tag.clone());
|
||||||
let value = command_dict(
|
let value = command_dict(
|
||||||
registry.get_command(&cmd).ok_or_else(|| {
|
registry.get_command(&cmd)?.ok_or_else(|| {
|
||||||
ShellError::labeled_error(
|
ShellError::labeled_error(
|
||||||
format!("Could not load {}", cmd),
|
format!("Could not load {}", cmd),
|
||||||
"could not load command",
|
"could not load command",
|
||||||
|
@ -71,7 +71,7 @@ impl PerItemCommand for Help {
|
||||||
|
|
||||||
help.push_back(ReturnSuccess::value(short_desc.into_value()));
|
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)? {
|
||||||
let mut long_desc = String::new();
|
let mut long_desc = String::new();
|
||||||
|
|
||||||
long_desc.push_str(&command.usage());
|
long_desc.push_str(&command.usage());
|
||||||
|
|
|
@ -106,14 +106,26 @@ pub fn filter_plugin(
|
||||||
let mut reader = BufReader::new(stdout);
|
let mut reader = BufReader::new(stdout);
|
||||||
|
|
||||||
let request = JsonRpc::new("begin_filter", call_info.clone());
|
let request = JsonRpc::new("begin_filter", call_info.clone());
|
||||||
let request_raw = serde_json::to_string(&request).unwrap();
|
let request_raw = serde_json::to_string(&request);
|
||||||
match stdin.write(format!("{}\n", request_raw).as_bytes()) {
|
|
||||||
|
match request_raw {
|
||||||
|
Err(_) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(Err(ShellError::labeled_error(
|
||||||
|
"Could not load json from plugin",
|
||||||
|
"could not load json from plugin",
|
||||||
|
&call_info.name_tag,
|
||||||
|
)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Ok(request_raw) => match stdin.write(format!("{}\n", request_raw).as_bytes()) {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let mut result = VecDeque::new();
|
let mut result = VecDeque::new();
|
||||||
result.push_back(Err(ShellError::unexpected(format!("{}", err))));
|
result.push_back(Err(ShellError::unexpected(format!("{}", err))));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
|
@ -179,8 +191,20 @@ pub fn filter_plugin(
|
||||||
Ok(params) => {
|
Ok(params) => {
|
||||||
let request: JsonRpc<std::vec::Vec<Value>> =
|
let request: JsonRpc<std::vec::Vec<Value>> =
|
||||||
JsonRpc::new("quit", vec![]);
|
JsonRpc::new("quit", vec![]);
|
||||||
let request_raw = serde_json::to_string(&request).unwrap();
|
let request_raw = serde_json::to_string(&request);
|
||||||
|
match request_raw {
|
||||||
|
Ok(request_raw) => {
|
||||||
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(Err(ShellError::untagged_runtime_error(format!(
|
||||||
|
"Error while processing begin_filter response: {:?} {}",
|
||||||
|
e, input
|
||||||
|
))));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
params
|
params
|
||||||
}
|
}
|
||||||
|
@ -221,8 +245,20 @@ pub fn filter_plugin(
|
||||||
let mut reader = BufReader::new(stdout);
|
let mut reader = BufReader::new(stdout);
|
||||||
|
|
||||||
let request = JsonRpc::new("filter", v);
|
let request = JsonRpc::new("filter", v);
|
||||||
let request_raw = serde_json::to_string(&request).unwrap();
|
let request_raw = serde_json::to_string(&request);
|
||||||
|
match request_raw {
|
||||||
|
Ok(request_raw) => {
|
||||||
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let mut result = VecDeque::new();
|
||||||
|
result.push_back(Err(ShellError::untagged_runtime_error(format!(
|
||||||
|
"Error while processing filter response: {:?}",
|
||||||
|
e
|
||||||
|
))));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
match reader.read_line(&mut input) {
|
match reader.read_line(&mut input) {
|
||||||
|
@ -304,22 +340,32 @@ pub fn sink_plugin(
|
||||||
let input: Vec<Value> = args.input.values.collect().await;
|
let input: Vec<Value> = args.input.values.collect().await;
|
||||||
|
|
||||||
let request = JsonRpc::new("sink", (call_info.clone(), input));
|
let request = JsonRpc::new("sink", (call_info.clone(), input));
|
||||||
let request_raw = serde_json::to_string(&request).unwrap();
|
let request_raw = serde_json::to_string(&request);
|
||||||
let mut tmpfile = tempfile::NamedTempFile::new().unwrap();
|
if let Ok(request_raw) = request_raw {
|
||||||
|
if let Ok(mut tmpfile) = tempfile::NamedTempFile::new() {
|
||||||
let _ = writeln!(tmpfile, "{}", request_raw);
|
let _ = writeln!(tmpfile, "{}", request_raw);
|
||||||
let _ = tmpfile.flush();
|
let _ = tmpfile.flush();
|
||||||
|
|
||||||
let mut child = std::process::Command::new(path)
|
let mut child = std::process::Command::new(path)
|
||||||
.arg(tmpfile.path())
|
.arg(tmpfile.path())
|
||||||
.spawn()
|
.spawn();
|
||||||
.expect("Failed to spawn child process");
|
|
||||||
|
|
||||||
|
if let Ok(mut child) = child {
|
||||||
let _ = child.wait();
|
let _ = child.wait();
|
||||||
|
|
||||||
// Needed for async_stream to type check
|
// Needed for async_stream to type check
|
||||||
if false {
|
if false {
|
||||||
yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value());
|
yield ReturnSuccess::value(UntaggedValue::nothing().into_untagged_value());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
yield Err(ShellError::untagged_runtime_error("Could not create process for sink command"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
yield Err(ShellError::untagged_runtime_error("Could not open file to send sink command message"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
yield Err(ShellError::untagged_runtime_error("Could not create message to sink command"));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
Ok(OutputStream::new(stream))
|
Ok(OutputStream::new(stream))
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,7 +179,7 @@ fn save(
|
||||||
break if !save_raw {
|
break if !save_raw {
|
||||||
if let Some(extension) = full_path.extension() {
|
if let Some(extension) = full_path.extension() {
|
||||||
let command_name = format!("to-{}", extension.to_string_lossy());
|
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 {
|
let new_args = RawCommandArgs {
|
||||||
host,
|
host,
|
||||||
ctrl_c,
|
ctrl_c,
|
||||||
|
|
|
@ -95,7 +95,7 @@ fn which(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let builtin = commands.has(&item);
|
let builtin = commands.has(&item)?;
|
||||||
if builtin {
|
if builtin {
|
||||||
yield ReturnSuccess::value(entry_builtin!(item, application.tag.clone()));
|
yield ReturnSuccess::value(entry_builtin!(item, application.tag.clone()));
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ fn which(
|
||||||
if let Ok(path) = ichwh::which(&item).await {
|
if let Ok(path) = ichwh::which(&item).await {
|
||||||
yield ReturnSuccess::value(entry_path!(item, path.into(), application.tag.clone()));
|
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()));
|
yield ReturnSuccess::value(entry_builtin!(item, application.tag.clone()));
|
||||||
} else if let Ok(path) = ichwh::which(&item).await {
|
} else if let Ok(path) = ichwh::which(&item).await {
|
||||||
yield ReturnSuccess::value(entry_path!(item, path.into(), application.tag.clone()));
|
yield ReturnSuccess::value(entry_path!(item, path.into(), application.tag.clone()));
|
||||||
|
|
|
@ -54,32 +54,46 @@ impl CommandRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_command(&self, name: &str) -> Option<Arc<Command>> {
|
pub(crate) fn get_command(&self, name: &str) -> Result<Option<Arc<Command>>, ShellError> {
|
||||||
let registry = self.registry.lock().unwrap();
|
let registry = self.registry.lock().map_err(|_| {
|
||||||
|
ShellError::untagged_runtime_error("Internal error: get_command could not get mutex")
|
||||||
|
})?;
|
||||||
|
|
||||||
registry.get(name).cloned()
|
Ok(registry.get(name).cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn expect_command(&self, name: &str) -> Result<Arc<Command>, ShellError> {
|
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))
|
ShellError::untagged_runtime_error(format!("Could not load command: {}", name))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn has(&self, name: &str) -> bool {
|
pub(crate) fn has(&self, name: &str) -> Result<bool, ShellError> {
|
||||||
let registry = self.registry.lock().unwrap();
|
let registry = self.registry.lock().map_err(|_| {
|
||||||
|
ShellError::untagged_runtime_error("Internal error: has could not get mutex")
|
||||||
|
})?;
|
||||||
|
|
||||||
registry.contains_key(name)
|
Ok(registry.contains_key(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert(&mut self, name: impl Into<String>, command: Arc<Command>) {
|
pub(crate) fn insert(
|
||||||
let mut registry = self.registry.lock().unwrap();
|
&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")
|
||||||
|
})?;
|
||||||
|
|
||||||
registry.insert(name.into(), command);
|
registry.insert(name.into(), command);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn names(&self) -> Vec<String> {
|
pub(crate) fn names(&self) -> Result<Vec<String>, ShellError> {
|
||||||
let registry = self.registry.lock().unwrap();
|
let registry = self.registry.lock().map_err(|_| {
|
||||||
registry.keys().cloned().collect()
|
ShellError::untagged_runtime_error("Internal error: names could not get mutex")
|
||||||
|
})?;
|
||||||
|
Ok(registry.keys().cloned().collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,13 +189,15 @@ impl Context {
|
||||||
block(&mut *errors)
|
block(&mut *errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_commands(&mut self, commands: Vec<Arc<Command>>) {
|
pub fn add_commands(&mut self, commands: Vec<Arc<Command>>) -> Result<(), ShellError> {
|
||||||
for command in commands {
|
for command in commands {
|
||||||
self.registry.insert(command.name().to_string(), command);
|
self.registry.insert(command.name().to_string(), command)?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_command(&self, name: &str) -> Option<Arc<Command>> {
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_command(&self, name: &str) -> Result<Option<Arc<Command>>, ShellError> {
|
||||||
self.registry.get_command(name)
|
self.registry.get_command(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl EvaluateTrait for Block {
|
||||||
return Ok(UntaggedValue::nothing().into_value(&self.tag));
|
return Ok(UntaggedValue::nothing().into_value(&self.tag));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut last = None;
|
let mut last = Ok(UntaggedValue::nothing().into_value(&self.tag));
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"EXPRS = {:?}",
|
"EXPRS = {:?}",
|
||||||
|
@ -54,15 +54,10 @@ impl EvaluateTrait for Block {
|
||||||
);
|
);
|
||||||
|
|
||||||
for expr in self.expressions.iter() {
|
for expr in self.expressions.iter() {
|
||||||
last = Some(evaluate_baseline_expr(
|
last = evaluate_baseline_expr(&expr, &CommandRegistry::empty(), &scope, &self.source)
|
||||||
&expr,
|
|
||||||
&CommandRegistry::empty(),
|
|
||||||
&scope,
|
|
||||||
&self.source,
|
|
||||||
)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(last.unwrap())
|
last
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_box(&self) -> Evaluate {
|
fn clone_box(&self) -> Evaluate {
|
||||||
|
@ -382,7 +377,7 @@ mod tests {
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.into_untagged_value()
|
.into_untagged_value()
|
||||||
.replace_data_at_column_path(&field_path?.item, replacement)
|
.replace_data_at_column_path(&field_path?.item, replacement)
|
||||||
.unwrap();
|
.ok_or_else(|| ShellError::untagged_runtime_error("Could not replace column"))?;
|
||||||
|
|
||||||
assert_eq!(actual, row(indexmap! {"amigos".into() => string("jonas")}));
|
assert_eq!(actual, row(indexmap! {"amigos".into() => string("jonas")}));
|
||||||
|
|
||||||
|
@ -411,9 +406,15 @@ mod tests {
|
||||||
let tag = replacement.tag.clone();
|
let tag = replacement.tag.clone();
|
||||||
|
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.into_value(tag.clone())
|
.into_value(&tag)
|
||||||
.replace_data_at_column_path(&field_path?.item, replacement.clone())
|
.replace_data_at_column_path(&field_path?.item, replacement.clone())
|
||||||
.unwrap();
|
.ok_or_else(|| {
|
||||||
|
ShellError::labeled_error(
|
||||||
|
"Could not replace column",
|
||||||
|
"could not replace column",
|
||||||
|
&tag,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual,
|
actual,
|
||||||
|
@ -467,7 +468,13 @@ mod tests {
|
||||||
let actual = sample
|
let actual = sample
|
||||||
.into_value(tag.clone())
|
.into_value(tag.clone())
|
||||||
.replace_data_at_column_path(&field_path?.item, replacement.clone())
|
.replace_data_at_column_path(&field_path?.item, replacement.clone())
|
||||||
.unwrap();
|
.ok_or_else(|| {
|
||||||
|
ShellError::labeled_error(
|
||||||
|
"Could not replace column",
|
||||||
|
"could not replace column",
|
||||||
|
&tag,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual,
|
actual,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![recursion_limit = "1024"]
|
#![recursion_limit = "2048"]
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl NuCompleter {
|
||||||
pos: usize,
|
pos: usize,
|
||||||
context: &rustyline::Context,
|
context: &rustyline::Context,
|
||||||
) -> rustyline::Result<(usize, Vec<rustyline::completion::Pair>)> {
|
) -> rustyline::Result<(usize, Vec<rustyline::completion::Pair>)> {
|
||||||
let commands: Vec<String> = self.commands.names();
|
let commands: Vec<String> = self.commands.names().unwrap_or_else(|_| vec![]);
|
||||||
|
|
||||||
let line_chars: Vec<_> = line[..pos].chars().collect();
|
let line_chars: Vec<_> = line[..pos].chars().collect();
|
||||||
|
|
||||||
|
|
|
@ -1047,7 +1047,13 @@ impl Shell for FilesystemShell {
|
||||||
}
|
}
|
||||||
|
|
||||||
if trash.item {
|
if trash.item {
|
||||||
SendToTrash::remove(path).unwrap();
|
SendToTrash::remove(path).map_err(|_| {
|
||||||
|
ShellError::labeled_error(
|
||||||
|
"Could not move file to trash",
|
||||||
|
"could not move to trash",
|
||||||
|
target.tag(),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
} else if path.is_dir() {
|
} else if path.is_dir() {
|
||||||
std::fs::remove_dir_all(&path)?;
|
std::fs::remove_dir_all(&path)?;
|
||||||
} else if path.is_file() {
|
} else if path.is_file() {
|
||||||
|
|
|
@ -21,13 +21,13 @@ pub struct HelpShell {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HelpShell {
|
impl HelpShell {
|
||||||
pub fn index(registry: &CommandRegistry) -> Result<HelpShell, std::io::Error> {
|
pub fn index(registry: &CommandRegistry) -> Result<HelpShell, ShellError> {
|
||||||
let mut cmds = TaggedDictBuilder::new(Tag::unknown());
|
let mut cmds = TaggedDictBuilder::new(Tag::unknown());
|
||||||
let mut specs = Vec::new();
|
let mut specs = Vec::new();
|
||||||
|
|
||||||
for cmd in registry.names() {
|
for cmd in registry.names()? {
|
||||||
let mut spec = TaggedDictBuilder::new(Tag::unknown());
|
let mut spec = TaggedDictBuilder::new(Tag::unknown());
|
||||||
let value = command_dict(registry.get_command(&cmd).unwrap(), Tag::unknown());
|
let value = command_dict(registry.get_command(&cmd)?.unwrap(), Tag::unknown());
|
||||||
|
|
||||||
spec.insert_untagged("name", cmd);
|
spec.insert_untagged("name", cmd);
|
||||||
spec.insert_untagged(
|
spec.insert_untagged(
|
||||||
|
@ -51,10 +51,7 @@ impl HelpShell {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_command(
|
pub fn for_command(cmd: Value, registry: &CommandRegistry) -> Result<HelpShell, ShellError> {
|
||||||
cmd: Value,
|
|
||||||
registry: &CommandRegistry,
|
|
||||||
) -> Result<HelpShell, std::io::Error> {
|
|
||||||
let mut sh = HelpShell::index(®istry)?;
|
let mut sh = HelpShell::index(®istry)?;
|
||||||
|
|
||||||
if let Value {
|
if let Value {
|
||||||
|
|
|
@ -96,7 +96,7 @@ fn filesystem_change_to_home_directory() {
|
||||||
"#
|
"#
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(PathBuf::from(actual), dirs::home_dir().unwrap());
|
assert_eq!(Some(PathBuf::from(actual)), dirs::home_dir());
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue