More ununwraps (#1152)

* More ununwraps

* More ununwraps

* Update completer.rs

* Update completer.rs
This commit is contained in:
Jonathan Turner 2020-01-03 06:51:20 +13:00 committed by GitHub
parent 3e3cb15f3d
commit 339a2de0eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 186 additions and 100 deletions

View file

@ -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,
)]); )])?;
} }
} }

View file

@ -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);

View file

@ -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(), )?,
)); ));
} }
_ => { _ => {

View file

@ -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)
} }
} }

View file

@ -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,

View file

@ -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(())
} }
} }

View file

@ -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());

View file

@ -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()) {
Ok(_) => {} match request_raw {
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::labeled_error(
"Could not load json from plugin",
"could not load json from plugin",
&call_info.name_tag,
)));
return result; return result;
} }
Ok(request_raw) => match stdin.write(format!("{}\n", request_raw).as_bytes()) {
Ok(_) => {}
Err(err) => {
let mut result = VecDeque::new();
result.push_back(Err(ShellError::unexpected(format!("{}", err))));
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);
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error match request_raw {
Ok(request_raw) => {
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);
let _ = stdin.write(format!("{}\n", request_raw).as_bytes()); // TODO: Handle error match request_raw {
Ok(request_raw) => {
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,21 +340,31 @@ 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 {
let _ = writeln!(tmpfile, "{}", request_raw); if let Ok(mut tmpfile) = tempfile::NamedTempFile::new() {
let _ = tmpfile.flush(); let _ = writeln!(tmpfile, "{}", request_raw);
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");
let _ = child.wait(); if let Ok(mut child) = child {
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))

View file

@ -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,

View file

@ -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()));

View file

@ -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)?;
} }
Ok(())
} }
pub(crate) fn get_command(&self, name: &str) -> Option<Arc<Command>> { pub(crate) fn get_command(&self, name: &str) -> Result<Option<Arc<Command>>, ShellError> {
self.registry.get_command(name) self.registry.get_command(name)
} }

View file

@ -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,

View file

@ -1,4 +1,4 @@
#![recursion_limit = "1024"] #![recursion_limit = "2048"]
#[cfg(test)] #[cfg(test)]
#[macro_use] #[macro_use]

View file

@ -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();

View file

@ -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() {

View 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(&registry)?; let mut sh = HelpShell::index(&registry)?;
if let Value { if let Value {

View file

@ -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());
}) })
} }