-
Couldn't load subscription status.
- Fork 226
Find/Replace Overlay: Restore cursor position when search input is cleared #3379
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
base: master
Are you sure you want to change the base?
Conversation
72bb8b1 to
7a05734
Compare
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.
@deepika-u thank you for working on this!
We already have a bunch of tests for the FindReplaceLogic as well as for the dialog and overlay UIs (in FindReplaceUITest). Could you please extend them with test methods to cover the use cases you address? That would help to verify the behavior (now and against regressions in the future), and it would also make it easier to understand how the additions are supposed to behave when one can just read the use cases in the form of tests.
Let me check on them and also test failures. Thanks for your time. |
0088837 to
22bbb44
Compare
|
@HeikoKlare |
22bbb44 to
46003dd
Compare
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.
Thank you for the contribution and the addition of tests!
I tested the improvement a bit and it generally it works quite fine for me. I found one use case that behaves different than what I would expect (see the comments for it). And currently the change looks more complex to me than it needs to be, but maybe I miss something when trying to understand the purpose of that code (also see one of the comments for this).
| // Initially empty find string | ||
| logic.setFindString(""); | ||
| // Now start a new search (transition empty -> non-empty) | ||
| logic.setFindString("beta"); |
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 it be better to use, e.g., "gamma" here, as (6,0) will now be both the position of the current incremental match as well as the restoreBaseLocation?
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.
Sounds reasonable, so updated the test case.
| // Now start a new search (transition empty -> non-empty) | ||
| logic.setFindString("beta"); | ||
| // Expect the stored restore location to match the caret before search started | ||
| assertThat(((FindReplaceLogic) logic).getRestoreBaseLocation(), is(new Point(6, 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.
It seems like this cast and exposing getRestoreBaseLocation() is only necessary for testing purposes. Since these tests are supposed to test the API, wouldn't it be better to test use cases of the API? E.g., a user is not interested in what the internal restoreBaseLocation value is (that's an implementation detail) but they are interested in the text viewer selection restoring to the original position after doing some search and then removing the find string again.
As an example, a test flow could be like this:
- Open document "alpha beta gamma"
- Set lection position in document to 6 (before "beta")
- Search for "gamma"
- Remove search input
- Expectation: selection position is 6 (whlie before implementing this feature it was 11)
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.
Even removed getRestoreBaseLocation(). Updated the test case in detail. Thanks.
| textViewer.setSelectedRange(6, 0); | ||
| logic.setFindString("beta"); | ||
| // Verify that restoreBaseLocation updated to the new caret position | ||
| assertThat(((FindReplaceLogic) logic).getRestoreBaseLocation(), is(new Point(6, 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.
I tested a similar scenario which does not currently not work, and I am not sure if it's intended or not:
- Open document "alpha beta gamma"
- Set selection in document to 0 (before "alpha")
- Search for "gamma"
- Set selection in document to 6 (before "beta")
- Remove the search input
I expect the cursor to move to the last selected position 6 (before "beta"), but I get the cursor at position 0, the one when find string was empty for the last time.
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 logic to capture restoreBaseLocation only triggers when transitioning from an empty to a non-empty find string (setFindString("") → setFindString("non-empty")).
In your case, you moved the caret after the search was already active, so the transition logic didn’t capture the new caret position.
In summary, also updated the test case. Your scenario fails because the caret must be moved before starting a new search string to capture the new base location. This is the behavior as per present design, based on the implementation in setFindString().
| if (isSetRestoreBaseLocation) { | ||
| restoreBaseLocation = incrementalBaseLocation; | ||
| isSetRestoreBaseLocation = false; | ||
| } |
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.
Can you explain the purpose of this code?
isSetRestoreBaseLocation seems to be initalized with true and is then set to false here, thus it's a one-time execution in the lifecycle of an instance of FindReplaceLogic. But to the best of my knowledge such an instance will live as long as an editor lives, which means that this code is just executed on first opening of a find/replace UI in that editor, and then it will never be executed again. And this first time happens right on initialization, as resetting the incremental base location happens when activating the INCREMENTAL search option. The restoreBaseLocation will only become relevant when a search string was entered and that will in every case happen after the incremental base position was set for the first time.
So I wonder if this code and the isSetRestoreBaseLocation field is necessary at all?
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.
Thanks for the thoughtful review! You're absolutely right that isSetRestoreBaseLocation is currently used as a one-time flag, and its lifecycle is tied to the first activation of incremental search.
The intent behind this logic was to ensure that when a user clears the search input, the cursor position is restored to where it was before the new search began. However, I now realize that setting restoreBaseLocation during resetIncrementalBaseLocation() (which happens early) may not align with the actual user action of starting a new search.
I agree that the isSetRestoreBaseLocation flag adds complexity and may not be necessary. Instead, I can simplify the logic by capturing the selection directly in setFindString() when transitioning from an empty to a non-empty string — which is the actual moment a new search begins. This way, restoreBaseLocation is set only when needed, and there's no need for a lifecycle flag.
I have revised the implementation accordingly to remove isSetRestoreBaseLocation and updated the logic.
| if (target != null) | ||
| restoreBaseLocation = target.getSelection(); |
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.
Please always put expression blocks into braces (applies in the same way also to other places in the PR).
| if (target != null) | |
| restoreBaseLocation = target.getSelection(); | |
| if (target != null) { | |
| restoreBaseLocation = target.getSelection(); | |
| } |
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.
Taken care, thanks.
|
Sorry, i couldnt reply on your comments as i had some workspace issues. Now all set, will check and reply on this. |
8fa82e1 to
c01ff0b
Compare
|
@HeikoKlare |
a new search pattern.
c01ff0b to
1364ad4
Compare
|
Mac failures cleared now. But seeing this issue now "05:42:31.581 [ERROR] Failed to execute goal org.eclipse.tycho:tycho-source-plugin:5.0.1-SNAPSHOT:plugin-source (plugin-source) on project org.eclipse.ui.workbench: Error creating source archive: Problem creating jar: Execution exception: Java heap space -> [Help 1] 05:42:31.581 [ERROR] ". |
Restores the editor caret to its original position when the Find/Replace overlay search field is cleared.
Fixes #1944
This change introduces logic to:
Also to test the new changes, test cases are added.
When a user begins a new search (transition from empty → non-empty search string), the current editor selection is stored as the base location.
When the search string becomes empty again, the stored selection is restored using IFindReplaceTargetExtension#setSelection(int, int).
Manual updates to the caret position followed by resetIncrementalBaseLocation() ensure that subsequent incremental searches start from the updated location.
The restore logic correctly refreshes between multiple search sessions, ensuring that the caret is not restored to stale positions.
Accordingly the below test cases are updated/added.
@HeikoKlare :
Can you have a look into this when you get some time please.