-
Notifications
You must be signed in to change notification settings - Fork 507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve error handling #299
Conversation
Thanks for opening this pull request! |
My approach currently is to:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏 👏 👏
I've learned a lot reading this. Thank you for your contribution!
…item + add test for this
…en input is empty.
…pose is to make place for a replacement.
The |
Would this be a bump in version to 2.4.0? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work!
I've never thought that error messages could serve as "documentation" for the source code.
My future work will surely be influenced by this PR.
Thanks again!
src/filesystem.rs
Outdated
io::BufReader::new(file) | ||
.lines() | ||
.map(|line| line.map_err(Error::from)) | ||
.collect::<Result<Vec<String>, Error>>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not well versed in Rust, but won't this collect
make the collection eager? If the file being parsed has 10,000 lines, won't this make the function read all these lines before we can process the first one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the Err
case it short circuits. But Ok
case it indeed allocates unnecessarily. Fixed!
// The dir might not exist which would throw an error. But here we don't care about that | ||
// since our purpose is to make space for a new directory. Potential other errors | ||
// (e.g due to lack of permission) will cause an error during dir creation. | ||
let _ = filesystem::remove_dir(&repo_path_str); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why using let _ =
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rust requires you to use the return value of remove_dir
. But as stated in the comment above it, we don't care about the potential Err
value. And the Ok
type is ()
anyway.
|
||
filesystem::remove_dir(&repo_path_str); | ||
filesystem::create_dir(&repo_path_str); | ||
// The dir might not exist which would throw an error. But here we don't care about that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you suggest another approach? I agree this is very error-prone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checking whether the dir exists before trying to remove it is a bit more robust, but not worth it imho. The check + remove is not atomic so remove_dir
would still be able to return the same errors. Just less frequently.
src/handler.rs
Outdated
Search { query } => flows::search::main(query.clone(), config), | ||
|
||
Query { query } => { | ||
let error_string = format!("Failed to filter cheatsheets for {}", &query); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't with_context
prevent us from generating this str 100% of the times?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
query
is part of config
. But config
is given away to flows::query::main
on :17, which makes it impossible to use query
after that. So we need to make a copy of query
before that happens.
let query_clone = query.clone()
and then passing that to with_context
would be a possibility. Not sure how smart the compiler is. I'll change it to be sure 🤔
} else if let [flag] = flag_and_value { | ||
Err(anyhow!("No value provided for the flag `{}`", flag)) | ||
} else { | ||
unreachable!() // Chunking by 2 allows only for tuples of 1 or 2 items... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use an else in the line 72 instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The chunks(2)
call on :46 returns slices (&[..]
) of the collection. The problem is that, despite telling chunks
that the slices should be 2
long, it doesn't know this at compile time. So Rust wants us to handle every possible case of slice length exhaustively.
Concrete this means that Rust would want the following let binding to be exhaustive.
} else {
let [flag] = flag_and_value;
Err(anyhow!("No value provided for the flag `{}`", flag))
}
You could do the following but obviously it wouldn't be as helpful an error:
} else {
Err(anyhow!("No value provided for a flag"))
}
|
||
#[derive(Error, Debug)] | ||
#[error( | ||
"\rHey listen! Navi encountered a problem. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😂
Congrats on merging your first pull request! |
PR for #291
fzf
andcore
modules.TODO:
bash
now has an error message similar to "Failed to execute bash". This should probably be related to the actual command ran, i.e. params given tobash
.anyhow::[with_]context()
is used to add, well, context. It might be better to create custom error variants for repetitive errors.navi fn welcome
is broken.navi repo browse
andnavi repo add https://github.com/denisidoro/navi
crash. Root cause isfzf
not returning data due to window layout error.