removed unwraps (#430)

This commit is contained in:
Fernando Herrera 2021-12-04 12:38:21 +00:00 committed by GitHub
parent eed22605ef
commit 8a06ea133b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 233 additions and 159 deletions

View file

@ -39,4 +39,4 @@ jobs:
- uses: actions-rs/cargo@v1
with:
command: clippy
args: -- -D warnings
args: -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect

View file

@ -114,11 +114,13 @@ fn into_int(
None => 10,
};
if !(2..=36).contains(&radix) {
return Err(ShellError::UnsupportedInput(
"Radix must lie in the range [2, 36]".to_string(),
options.radix.unwrap().span().unwrap(),
));
if let Some(val) = &options.radix {
if !(2..=36).contains(&radix) {
return Err(ShellError::UnsupportedInput(
"Radix must lie in the range [2, 36]".to_string(),
val.span()?,
));
}
}
input.map(

View file

@ -139,11 +139,13 @@ fn string_helper(
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
let config = stack.get_config()?;
if decimals && decimals_value.is_some() && decimals_value.unwrap().is_negative() {
return Err(ShellError::UnsupportedInput(
"Cannot accept negative integers for decimals arguments".to_string(),
head,
));
if let Some(decimal_val) = decimals_value {
if decimals && decimal_val.is_negative() {
return Err(ShellError::UnsupportedInput(
"Cannot accept negative integers for decimals arguments".to_string(),
head,
));
}
}
input.map(
@ -192,7 +194,7 @@ pub fn action(
}
Value::Float { val, .. } => {
if decimals {
let decimal_value = digits.unwrap() as usize;
let decimal_value = digits.unwrap_or(2) as usize;
Value::String {
val: format!("{:.*}", decimal_value, val),
span,

View file

@ -49,7 +49,7 @@ impl Command for Cp {
let interactive = call.has_flag("interactive");
let force = call.has_flag("force");
let path: PathBuf = current_dir().unwrap();
let path = current_dir()?;
let source = path.join(source.as_str());
let destination = path.join(destination.as_str());
@ -83,12 +83,36 @@ impl Command for Cp {
let prompt = format!(
"Are you shure that you want to copy {} to {}?",
file.as_ref()
.unwrap()
.map_err(|err| ShellError::LabeledError(
"Reference error".into(),
err.to_string(),
call.head
))?
.file_name()
.unwrap()
.ok_or_else(|| ShellError::LabeledError(
"File name error".into(),
"Unable to get file name".into(),
call.head
))?
.to_str()
.unwrap(),
destination.file_name().unwrap().to_str().unwrap()
.ok_or_else(|| ShellError::LabeledError(
"Unable to get str error".into(),
"Unable to convert to str file name".into(),
call.head
))?,
destination
.file_name()
.ok_or_else(|| ShellError::LabeledError(
"File name error".into(),
"Unable to get file name".into(),
call.head
))?
.to_str()
.ok_or_else(|| ShellError::LabeledError(
"Unable to get str error".into(),
"Unable to convert to str file name".into(),
call.head
))?,
);
let input = get_interactive_confirmation(prompt)?;

View file

@ -55,7 +55,13 @@ impl Command for Ls {
};
let call_span = call.head;
let glob = glob::glob(&pattern).unwrap();
let glob = glob::glob(&pattern).map_err(|err| {
nu_protocol::ShellError::LabeledError(
"Error extracting glob pattern".into(),
err.to_string(),
call.head,
)
})?;
Ok(glob
.into_iter()

View file

@ -5,7 +5,7 @@ use super::util::get_interactive_confirmation;
use nu_engine::CallExt;
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, PipelineData, ShellError, Signature, SyntaxShape};
use nu_protocol::{Category, PipelineData, ShellError, Signature, Spanned, SyntaxShape};
#[derive(Clone)]
pub struct Mv;
@ -45,22 +45,20 @@ impl Command for Mv {
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
// TODO: handle invalid directory or insufficient permissions when moving
let source: String = call.req(engine_state, stack, 0)?;
let spanned_source: Spanned<String> = call.req(engine_state, stack, 0)?;
let destination: String = call.req(engine_state, stack, 1)?;
let interactive = call.has_flag("interactive");
let force = call.has_flag("force");
let path: PathBuf = current_dir().unwrap();
let source = path.join(source.as_str());
let path: PathBuf = current_dir()?;
let source = path.join(spanned_source.item.as_str());
let destination = path.join(destination.as_str());
let mut sources =
glob::glob(&source.to_string_lossy()).map_or_else(|_| Vec::new(), Iterator::collect);
if sources.is_empty() {
return Err(ShellError::FileNotFound(
call.positional.first().unwrap().span,
));
return Err(ShellError::FileNotFound(spanned_source.span));
}
if interactive && !force {
@ -69,12 +67,36 @@ impl Command for Mv {
let prompt = format!(
"Are you shure that you want to move {} to {}?",
file.as_ref()
.unwrap()
.map_err(|err| ShellError::LabeledError(
"Reference error".into(),
err.to_string(),
call.head
))?
.file_name()
.unwrap()
.ok_or_else(|| ShellError::LabeledError(
"File name error".into(),
"Unable to get file name".into(),
call.head
))?
.to_str()
.unwrap(),
destination.file_name().unwrap().to_str().unwrap()
.ok_or_else(|| ShellError::LabeledError(
"Unable to get str error".into(),
"Unable to convert to str file name".into(),
call.head
))?,
destination
.file_name()
.ok_or_else(|| ShellError::LabeledError(
"File name error".into(),
"Unable to get file name".into(),
call.head
))?
.to_str()
.ok_or_else(|| ShellError::LabeledError(
"Unable to get str error".into(),
"Unable to convert to str file name".into(),
call.head
))?,
);
let input = get_interactive_confirmation(prompt)?;

View file

@ -84,23 +84,6 @@ fn rm(
"Can't use \"--trash\" with \"--permanent\"".to_string(),
call.head,
));
// let trash_span = call.get_flag_expr("trash").unwrap().span;
// let perm_span = call.get_flag_expr("permanent").unwrap().span;
// let left_message = "cannot use".to_string();
// let right_message = "with".to_string();
// let (left_span, right_span) = match trash_span.start < perm_span.start {
// true => (trash_span, perm_span),
// false => (perm_span, trash_span),
// };
// return Err(ShellError::IncompatibleParameters {
// left_message,
// left_span,
// right_message,
// right_span,
// });
}
let current_path = current_dir()?;
@ -141,7 +124,19 @@ fn rm(
for (index, file) in targets.iter().enumerate() {
let prompt: String = format!(
"Are you sure that you what to delete {}?",
file.1.file_name().unwrap().to_str().unwrap()
file.1
.file_name()
.ok_or_else(|| ShellError::LabeledError(
"File name error".into(),
"Unable to get file name".into(),
call.head
))?
.to_str()
.ok_or_else(|| ShellError::LabeledError(
"Unable to get str error".into(),
"Unable to convert to str file name".into(),
call.head
))?,
);
let input = get_interactive_confirmation(prompt)?;
@ -192,9 +187,18 @@ fn rm_helper(call: &Call, args: RmArgs) -> Vec<Value> {
#[cfg(not(feature = "trash-support"))]
{
if trash {
return vec![Value::Error {
error: ShellError::FeatureNotEnabled(call.get_flag_expr("trash").unwrap().span),
}];
let error = match call.get_flag_expr("trash").ok_or_else(|| {
ShellError::LabeledError(
"Flag not found".into(),
"trash flag not found".into(),
call.head,
)
}) {
Ok(expr) => ShellError::FeatureNotEnabled(expr.span),
Err(err) => err,
};
return vec![Value::Error { error }];
}
}

View file

@ -6,7 +6,6 @@ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
use std::convert::TryInto;
#[derive(Clone)]
pub struct Drop;
@ -90,7 +89,7 @@ impl Command for Drop {
vlen - rows_to_drop
};
let iter = v.into_iter().take(k.try_into().unwrap());
let iter = v.into_iter().take(k as usize);
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}
}

View file

@ -72,7 +72,17 @@ fn first_helper(
let mut input_peek = input.into_iter().peekable();
if input_peek.peek().is_some() {
match input_peek.peek().unwrap().get_type() {
match input_peek
.peek()
.ok_or_else(|| {
ShellError::LabeledError(
"Error in first".into(),
"unable to pick on next value".into(),
call.head,
)
})?
.get_type()
{
Type::Binary => {
match &mut input_peek.next() {
Some(v) => match &v {

View file

@ -6,7 +6,6 @@ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
use std::convert::TryInto;
#[derive(Clone)]
pub struct Last;
@ -53,9 +52,7 @@ impl Command for Last {
let vlen: i64 = v.len() as i64;
let beginning_rows_to_skip = rows_to_skip(vlen, rows);
let iter = v
.into_iter()
.skip(beginning_rows_to_skip.try_into().unwrap());
let iter = v.into_iter().skip(beginning_rows_to_skip as usize);
Ok(iter.into_pipeline_data(engine_state.ctrlc.clone()))
}

View file

@ -1,3 +1,5 @@
use std::cmp::Ordering;
use crate::math::avg::average;
use crate::math::utils::run_with_function;
use nu_protocol::ast::Call;
@ -72,14 +74,14 @@ pub fn median(values: &[Value], head: &Span) -> Result<Value, ShellError> {
rhs_span: elem[1].span()?,
});
}
Ok(elem[0].partial_cmp(&elem[1]).unwrap())
Ok(elem[0].partial_cmp(&elem[1]).unwrap_or(Ordering::Equal))
})
.find(|elem| elem.is_err())
{
return Err(values);
}
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
match take {
Pick::Median => {

View file

@ -78,7 +78,7 @@ pub fn mode(values: &[Value], head: &Span) -> Result<Value, ShellError> {
rhs_span: elem[1].span()?,
});
}
Ok(elem[0].partial_cmp(&elem[1]).unwrap())
Ok(elem[0].partial_cmp(&elem[1]).unwrap_or(Ordering::Equal))
})
.find(|elem| elem.is_err())
{
@ -87,7 +87,7 @@ pub fn mode(values: &[Value], head: &Span) -> Result<Value, ShellError> {
//In e-q, Value doesn't implement Hash or Eq, so we have to get the values inside
// But f64 doesn't implement Hash, so we get the binary representation to use as
// key in the HashMap
let hashable_values: Result<Vec<HashableType>, ShellError> = values
let hashable_values = values
.iter()
.map(|val| match val {
Value::Int { val, .. } => Ok(HashableType::new(val.to_ne_bytes(), NumberTypes::Int)),
@ -102,16 +102,13 @@ pub fn mode(values: &[Value], head: &Span) -> Result<Value, ShellError> {
}
other => Err(ShellError::UnsupportedInput(
"Unable to give a result with this input".to_string(),
other.span().unwrap(),
other.span()?,
)),
})
.collect::<Result<Vec<HashableType>, ShellError>>();
if let Err(not_hashable) = hashable_values {
return Err(not_hashable);
}
.collect::<Result<Vec<HashableType>, ShellError>>()?;
let mut frequency_map = std::collections::HashMap::new();
for v in hashable_values.unwrap() {
for v in hashable_values {
let counter = frequency_map.entry(v).or_insert(0);
*counter += 1;
}
@ -132,7 +129,7 @@ pub fn mode(values: &[Value], head: &Span) -> Result<Value, ShellError> {
}
}
modes.sort_by(|a, b| a.partial_cmp(b).unwrap());
modes.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));
Ok(Value::List {
vals: modes,
span: *head,

View file

@ -84,10 +84,27 @@ impl Command for Kill {
{
return Err(ShellError::IncompatibleParameters {
left_message: "force".to_string(),
left_span: call.get_named_arg("force").unwrap().span,
left_span: call
.get_named_arg("force")
.ok_or_else(|| {
ShellError::LabeledError(
"Flag error".into(),
"flag force not found".into(),
call.head,
)
})?
.span,
right_message: "signal".to_string(),
right_span: span(&[
call.get_named_arg("signal").unwrap().span,
call.get_named_arg("signal")
.ok_or_else(|| {
ShellError::LabeledError(
"Flag error".into(),
"flag signal not found".into(),
call.head,
)
})?
.span,
signal_span,
]),
});

View file

@ -38,7 +38,7 @@ impl Command for Format {
match specified_pattern {
Err(e) => Err(e),
Ok(pattern) => {
let string_pattern = pattern.as_string().unwrap();
let string_pattern = pattern.as_string()?;
let ops = extract_formatting_operations(string_pattern);
format(input, &ops, call.head)
}
@ -184,9 +184,7 @@ fn format_record(
val: col_name.clone(),
span: Span::unknown(),
}]) {
Ok(value_at_column) => {
output.push_str(value_at_column.as_string().unwrap().as_str())
}
Ok(value_at_column) => output.push_str(value_at_column.as_string()?.as_str()),
Err(se) => return Err(se),
}
}

View file

@ -142,7 +142,7 @@ fn action(
span: head,
}
} else {
let c = character.as_ref().unwrap(); // we already know this flag needs to exist because the command is type checked before we call the action function
let c = character.as_ref().expect("we already know this flag needs to exist because the command is type checked before we call the action function");
let mut res = c.repeat(s - val.chars().count());
res += val;
Value::String {

View file

@ -143,7 +143,7 @@ fn action(
}
} else {
let mut res = val.to_string();
res += &character.as_ref().unwrap().repeat(s - val.chars().count());
res += &character.as_ref().expect("we already know this flag needs to exist because the command is type checked before we call the action function").repeat(s - val.chars().count());
Value::String {
val: res,
span: head,

View file

@ -143,7 +143,7 @@ where
input,
);
let to_trim = match options.character.as_ref() {
Some(v) => v.as_string().unwrap().chars().next(),
Some(v) => v.as_string()?.chars().next(),
None => None,
};

View file

@ -59,19 +59,21 @@ impl Command for External {
args,
last_expression,
env_vars,
call,
};
command.run_with_input(engine_state, input, config)
}
}
pub struct ExternalCommand {
pub struct ExternalCommand<'call> {
pub name: Spanned<String>,
pub args: Vec<String>,
pub last_expression: bool,
pub env_vars: HashMap<String, String>,
pub call: &'call Call,
}
impl ExternalCommand {
impl<'call> ExternalCommand<'call> {
pub fn run_with_input(
&self,
engine_state: &EngineState,
@ -84,7 +86,8 @@ impl ExternalCommand {
// TODO. We don't have a way to know the current directory
// This should be information from the EvaluationContex or EngineState
let path = env::current_dir().unwrap();
let path = env::current_dir()?;
process.current_dir(path);
process.envs(&self.env_vars);
@ -145,16 +148,12 @@ impl ExternalCommand {
// If this external is not the last expression, then its output is piped to a channel
// and we create a ValueStream that can be consumed
if !last_expression {
let stdout = child
.stdout
.take()
.ok_or_else(|| {
ShellError::ExternalCommand(
"Error taking stdout from external".to_string(),
span,
)
})
.unwrap();
let stdout = child.stdout.take().ok_or_else(|| {
ShellError::ExternalCommand(
"Error taking stdout from external".to_string(),
span,
)
})?;
// Stdout is read using the Buffer reader. It will do so until there is an
// error or there are no more bytes to read

View file

@ -5,7 +5,8 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, PathMember},
engine::{Command, EngineState, Stack},
Category, Config, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Value,
Category, Config, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
};
use nu_term_grid::grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions};
use terminal_size::{Height, Width};
@ -76,7 +77,7 @@ prints out the list properly."#
separator_param,
env_str,
use_grid_icons,
))
)?)
} else {
Ok(PipelineData::new(call.head))
}
@ -93,7 +94,7 @@ prints out the list properly."#
separator_param,
env_str,
use_grid_icons,
))
)?)
} else {
// dbg!(data);
Ok(PipelineData::new(call.head))
@ -115,7 +116,7 @@ prints out the list properly."#
separator_param,
env_str,
use_grid_icons,
))
)?)
}
x => {
// dbg!("other value");
@ -142,7 +143,7 @@ fn create_grid_output(
separator_param: Option<String>,
env_str: Option<String>,
use_grid_icons: bool,
) -> PipelineData {
) -> Result<PipelineData, ShellError> {
let ls_colors = match env_str {
Some(s) => LsColors::from_string(&s),
None => LsColors::default(),
@ -173,7 +174,7 @@ fn create_grid_output(
if use_grid_icons {
let no_ansi = strip_ansi(&value);
let path = std::path::Path::new(&no_ansi);
let icon = icon_for_file(path);
let icon = icon_for_file(path)?;
let ls_colors_style = ls_colors.style_for_path(path);
// eprintln!("ls_colors_style: {:?}", &ls_colors_style);
@ -212,18 +213,20 @@ fn create_grid_output(
}
}
if let Some(grid_display) = grid.fit_into_width(cols as usize) {
Value::String {
val: grid_display.to_string(),
span: call.head,
Ok(
if let Some(grid_display) = grid.fit_into_width(cols as usize) {
Value::String {
val: grid_display.to_string(),
span: call.head,
}
} else {
Value::String {
val: format!("Couldn't fit grid into {} columns!", cols),
span: call.head,
}
}
} else {
Value::String {
val: format!("Couldn't fit grid into {} columns!", cols),
span: call.head,
}
}
.into_pipeline_data()
.into_pipeline_data(),
)
}
fn convert_to_list(

View file

@ -1,4 +1,5 @@
use lazy_static::lazy_static;
use nu_protocol::{ShellError, Span};
use std::collections::HashMap;
use std::path::Path;
@ -129,23 +130,47 @@ lazy_static! {
};
}
pub fn icon_for_file(file_path: &Path) -> char {
pub fn icon_for_file(file_path: &Path) -> Result<char, ShellError> {
let extensions = Box::new(FileExtensions);
let fp = format!("{}", file_path.display());
if let Some(icon) = MAP_BY_NAME.get(&fp[..]) {
*icon
Ok(*icon)
} else if file_path.is_dir() {
match file_path.file_name().unwrap().to_str().unwrap() {
let str = file_path
.file_name()
.ok_or_else(|| {
ShellError::LabeledError(
"File name error".into(),
"Unable to get file name".into(),
Span::unknown(),
)
})?
.to_str()
.ok_or_else(|| {
ShellError::LabeledError(
"Unable to get str error".into(),
"Unable to convert to str file name".into(),
Span::unknown(),
)
})?;
Ok(match str {
"bin" => '\u{e5fc}', // 
".git" => '\u{f1d3}', // 
".idea" => '\u{e7b5}', // 
_ => '\u{f115}', // 
}
})
} else if let Some(icon) = extensions.icon_file(file_path) {
icon
Ok(icon)
} else if let Some(ext) = file_path.extension().as_ref() {
match ext.to_str().unwrap() {
let str = ext.to_str().ok_or_else(|| {
ShellError::LabeledError(
"Unable to get str error".into(),
"Unable to convert to str file name".into(),
Span::unknown(),
)
})?;
Ok(match str {
"ai" => '\u{e7b4}', // 
"android" => '\u{e70e}', // 
"apk" => '\u{e70e}', // 
@ -372,9 +397,9 @@ pub fn icon_for_file(file_path: &Path) -> char {
"zsh-theme" => '\u{f489}', // 
"zshrc" => '\u{f489}', // 
_ => '\u{f15b}', // 
}
})
} else {
'\u{f016}'
Ok('\u{f016}')
}
}

View file

@ -62,7 +62,7 @@ impl Value {
let (cols, vals) = value.as_record()?;
let mut hm = HashMap::new();
for (k, v) in cols.iter().zip(vals) {
hm.insert(k.to_string(), v.as_string().unwrap());
hm.insert(k.to_string(), v.as_string()?);
}
config.color_config = hm;
}

View file

@ -227,13 +227,14 @@ impl EngineState {
let path = decl.is_plugin().expect("plugin should have file name");
let file_name = path.to_str().expect("path should be a str");
let line = serde_json::to_string_pretty(&decl.signature())
serde_json::to_string_pretty(&decl.signature())
.map(|signature| format!("register {} {}\n\n", file_name, signature))
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
plugin_file
.write_all(line.as_bytes())
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))
.and_then(|line| {
plugin_file
.write_all(line.as_bytes())
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))
})?;
}
Ok(())
} else {
@ -248,40 +249,6 @@ impl EngineState {
}
}
#[cfg(feature = "plugin")]
pub fn update_plugin_file_1(&self) -> Result<(), ShellError> {
use std::io::Write;
// Updating the signatures plugin file with the added signatures
if let Some(plugin_path) = &self.plugin_signatures {
// Always creating the file which will erase previous signatures
let mut plugin_file = std::fs::File::create(plugin_path.as_path())
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
// Plugin definitions with parsed signature
for decl in self.plugin_decls() {
// A successful plugin registration already includes the plugin filename
// No need to check the None option
let path = decl.is_plugin().expect("plugin should have file name");
let file_name = path.to_str().expect("path should be a str");
let line = serde_json::to_string_pretty(&decl.signature())
.map(|signature| format!("register {} {}\n\n", file_name, signature))
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
plugin_file
.write_all(line.as_bytes())
.map_err(|err| ShellError::PluginFailedToLoad(err.to_string()))?;
}
Ok(())
} else {
Err(ShellError::PluginFailedToLoad(
"Plugin file not found".into(),
))
}
}
pub fn num_files(&self) -> usize {
self.files.len()
}

View file

@ -875,7 +875,7 @@ impl WrappedTable {
break;
}
writeln!(&mut total_output, "{}", output).unwrap();
writeln!(&mut total_output, "{}", output).expect("writing should be done to buffer");
}
total_output
}

View file

@ -64,7 +64,7 @@ impl CompletionActionHandler for FuzzyCompletion {
.default(0)
.items(&selections[..])
.interact_on_opt(&Term::stdout())
.unwrap();
.expect("Fuzzy completion interact on operation");
let _ = crossterm::terminal::enable_raw_mode();
if let Some(result) = result {
@ -85,7 +85,7 @@ fn main() -> Result<()> {
// miette::set_panic_hook();
let miette_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |x| {
crossterm::terminal::disable_raw_mode().unwrap();
crossterm::terminal::disable_raw_mode().expect("unable to disable raw mode");
miette_hook(x);
}));