-
Notifications
You must be signed in to change notification settings - Fork 10
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
Refactor paths(with tests) and bulk operations #87
Refactor paths(with tests) and bulk operations #87
Conversation
Add tests to increase confidence in correctness
Add MultiNormal mode and ProccessAction for repeating actions
Command -> Normal MultiNormal -> Normal
Reduce code duplication
Functioning multiple move and delete
2a02a5c
to
46c4416
Compare
@gurgalex Great work! Code review inc... But first, initial thoughts: |
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 think that's all I have for right now, mostly just my two cents. I'm probably going to look at it again at a later point, maybe tomorrow I don't know.
As per usual @gurgalex really good code I just think there are some things that maybe would make your life easier. ❤️
src/program/command_mode.rs
Outdated
Some(self.paths.images[self.paths.index].to_owned()) | ||
} else { | ||
None | ||
let target_path = match self.paths.current_image_path() { |
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 this instance, sorry if this was unclear, we want the image path at the current index because we want to find the current image if it occurs in the new glob.
In this match it returns, but it really should just be None, because we have no image to find.
This causes newglob
to fail on a start that is empty, your comment is right we don't have any images, but that's a 👌
This is why later on in Development
there's this
if let Some(target_path) = target { // <---- here, because we don't have any images
// find location of current image, if it exists in self.paths.images
match self
.paths
.images
.iter()
.position(|path| path == &target_path)
{
Some(new_index) => self.paths.index = new_index,
None => {
self.paths.index = 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.
Believe this is fixed with the latest changes.
pub fn skip_forward(&mut self) -> Result<(), String> { | ||
let skip_size = compute_skip_size(&self.paths.images); | ||
self.increment(skip_size) | ||
pub fn skip_forward(&mut self, times: usize) -> Result<(), String> { |
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.
So Okay, I could be wrong here, but hear me out.
So in every function you have it taking a usize
called times
. This is a suitable solution, but they all have the same function definition... pub fn name(&mut self, times: usize) -> Result<(), String>
There's gotta be a way to simplify this down, right? Using generics and using functions?
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.
Repeating of function signatures seems fine, as each does something different.
I'm mostly concerned with the near duplication that run_multi_normal_mode
does of run_normal_mode
https://github.com/Davejkane/riv/pull/87/files#diff-52fc4303c2b25fd9f3edcce1fbd21455R497
src/program/mod.rs
Outdated
} => match (a, n) { | ||
(Action::Backspace, _) => { | ||
// Divide repeat by int 10 to remove last digit | ||
self.ui_state.repeat /= 10; |
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.
@Davejkane I'm not sure on how you want this to perform, but in Vim if you backspace at any point it just clears the entire buffer rather than removing one of the numbers.
src/program/render.rs
Outdated
@@ -366,6 +371,7 @@ fn normal_help_text() -> Vec<&'static str> { | |||
"+------------+----------------------------+-----------------------------------------------------+", | |||
"| Key 1 | Key 2 | Action |", | |||
"+------------+----------------------------+-----------------------------------------------------+", | |||
"| 0-9 | | Perform the below actions in bulk |", |
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.
This is a huge nitpick, but maybe include that it takes one of the below operations?
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.
True
In the Key 2 slot.
Text: Key of the action to perform
|
||
/// Perform an Action `times` times | ||
#[derive(Clone, Debug)] | ||
pub struct ProcessAction<'a> { |
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.
If you're just associating two variables, why not use a tuple? Is there a benefit of a struct
versus a tuple?
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 went with a struct for the labeled fields (action, and times).
Also being able to implement conversions (such as from ProcessAction -> MultiAction)
"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" => { | ||
let previous_count = state.repeat; | ||
// Safe to unwrap as only digits were matched | ||
let next_digit = text.parse::<usize>().unwrap(); |
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 parse and add it on here? Instead of just storing it in a String
or maybe Cow
borrowed string and then when the user hits an action then parse it? This would also make it so you don't have to divide by 10 in mod.rs
to truncate a digit
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.
Parsing immediately was one way to reduce code duplication when the text is not 0-9
.
The amount of times would not have to be parsed on every action.
I think I could move the parsing out of the ui
event -> MultiNormalAction translation if Normal mode read from the same field repeat
.
src/ui.rs
Outdated
let first_digit = text.parse::<usize>().unwrap(); | ||
// Save the first digit before switching | ||
state.repeat = first_digit; | ||
Action::SwitchMultiNormalMode |
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.
As stated above, maybe have the Mode
store the number of times to repeat? (As a String or Cow maybe?) I don't know enough about Cow yet...
The artificial length is the images vec length unless capped by the user
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.
@gurgalex, first off thanks for the great work. I knew this would probably be our biggest feature to date, but it's also the feature that's really going to make riv unique, so thanks for taking it on.
I haven't had time just yet to do some proper code review, but I have had the chance to do some QA.
When I use 23j
for instance, after rendering the 23, it then renders the old index very briefly before rendering the new index. It's jarring. But this could potentially be taken care of by rendering the number at the right side of the bar along with the rest of the bar.
I want 56G
to go the 56th image exactly. but right now it goes to the end. That's a feature request.
I want the dot operator to work with bulk operations. If I press 10k
then I want every .
press to also be 10k
. Currently .
will just be k
.
Only update display in MultiNormal when deleting digits
@Davejkane Did you want the dot presses to multiply as well? |
…efactor_paths_and_test_bulk_operations
@Davejkane |
I just checked with vim and it appears that the way you're doing it, without multiplication is correct. I'll try to get around to code review today. |
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.
This all looks great to me. Really good job. Please squash and merge and tidy up the commit message.
Closes #48
cc: @Davejkane
why the refactor of paths?
Making the indexes and images fields private forces the user of access methods which at least make the caller consider the possibility of no images being present.
With private fields, removing an image must be done by calling a method which does the proper manipulations for the user.
Some methods now can limit how much mutable access (if at all) is given to the images vec. For instance, sorting the vector can do everything except that which alters its length.
Some areas only need read access, so no need to give the ability to replace the whole vec outright.
A dedicated
reload_imags
method is provided for this, which always makes sure the current image index is not larger than the last element's index.private fields seemed to aid in writing tests as well.
MultiNormal mode
Typing numbers on either the numpad or keyboard while in Normal mode will now switch to MultiNormal mode. This allows for performing many repetitions of Normal actions, but in bulk, like jumping 10 images ahead.
Concerns with MultiNormal implementation
Lots of code duplication between handling of actions of MultiNormal and Normal mode. Any ideas for somewhat merging the two modes?
Should actions that can only be performed once (like toggling fullscreen) be allowed as actions in MultiNormal mode. Example
22f
would only toggle the state of fullscreen once.Infobar display of times to repeat. Should the numbers be on the right like vim?
Small changes
process_action
. It is present only once for each mode, instead of needing duplication on every keypress/text match.