Skip to content
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

Fix #206511: Shortcuts now visit the correct search entry after editing #209228

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

andremmsilva
Copy link

@andremmsilva andremmsilva commented Mar 31, 2024

Fixes #206511
Bug (previous behavior):
Press Ctrl+Shift+F to perform a search.
Press F4 a few times.
Edit the selected result so it no longer matches the query.
The active position in the search pane disappears.
Press F4. Editor location jumps to the first found item.

Solution:
When the search results change, the tree in src/vs/workbench/contrib/search/browser/searchView.ts now correctly updates the selected result if it is no longer present. This is accomplished by keeping a reference to the Match immediately before the selection. If the tree's selection is deleted, we will find this reference and make this the new selection.

Testing:
This is tested via a smoke test, which attempts to perform deletions via the keyboard shortcuts in order to keep only the results in the first FileMatch.

@andremmsilva
Copy link
Author

@microsoft-github-policy-service agree

@andremmsilva andremmsilva marked this pull request as draft March 31, 2024 22:48
@andremmsilva andremmsilva deleted the fix-206511 branch March 31, 2024 22:52
@andremmsilva andremmsilva restored the fix-206511 branch March 31, 2024 22:53
@andremmsilva andremmsilva reopened this Apr 1, 2024
…ter editing

Bug (previous behavior):
    Press Ctrl+Shift+F to perform a search.
    Press F4 a few times.
    Edit the selected result so it no longer matches the query.
	The active position in the search pane disappears.
    Press F4. Editor location jumps to the first found item.

Solution:
When the search results change, the tree in src/vs/workbench/contrib/search/browser/searchView.ts now correctly updates the selected result if it is no longer present.
This is accomplished by keeping a reference to the Match immediately before the selection.
If the tree's selection is deleted, we will find this reference and make this the new selection.

Testing:
This is tested via a smoke test, which attempts to perform deletions via the keyboard shortcuts in order to keep only the results in the first FileMatch.
@andremmsilva
Copy link
Author

Hi! I’m sorry, I’m a bit new to the open source development community and didn’t expect my own smoke test to fail when I opened the PR. It was running fine on my codespace. The actual fix works perfectly fine though.

@andremmsilva andremmsilva marked this pull request as ready for review April 1, 2024 11:39
The test now uses the editor testing api to change the text in the files.
It also uses waitForTextContent on the selected plain match to make sure
the selection is correct.
@andremmsilva
Copy link
Author

Hello @andreamah! Sorry for the mess, once again, I'm still a bit inexperienced. The fix and tests should be working now :)

this.tree.expand(beforePrevious);
}

beforePrevious = navigator.previous();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before before this step, is the navigator's current selection still on the node that is either now non-existing or isn't a match? Just want to know without running the debugger 😅

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The navigator.current() result after navigating to selection (line 750) will point to the node that is now non-existing. However, because the tree results aren't updated yet, I can get the previous node (which still exists) and then use it to set the selection when the current is deleted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Can you check the event variable for removed: true for this so that it doesn't run every time we refresh the tree?

@andreamah
Copy link
Contributor

I wonder: would we expect the next entry to be highlighted instead of the previous? This might be more expected, and we already have logic for highlighting next match here

export function getElementToFocusAfterRemoved(viewer: WorkbenchCompressibleObjectTree<RenderableMatch>, element: RenderableMatch, elementsToRemove: RenderableMatch[]): RenderableMatch | undefined {
const navigator: ITreeNavigator<any> = viewer.navigate(element);
if (element instanceof FolderMatch) {
while (!!navigator.next() && (!(navigator.current() instanceof FolderMatch) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) { }
} else if (element instanceof FileMatch) {
while (!!navigator.next() && (!(navigator.current() instanceof FileMatch) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) {
viewer.expand(navigator.current());
}
} else {
while (navigator.next() && (!(navigator.current() instanceof Match) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) {
viewer.expand(navigator.current());
}
}
return navigator.current();
}

@andremmsilva
Copy link
Author

I wonder: would we expect the next entry to be highlighted instead of the previous? This might be more expected, and we already have logic for highlighting next match here

export function getElementToFocusAfterRemoved(viewer: WorkbenchCompressibleObjectTree<RenderableMatch>, element: RenderableMatch, elementsToRemove: RenderableMatch[]): RenderableMatch | undefined {
const navigator: ITreeNavigator<any> = viewer.navigate(element);
if (element instanceof FolderMatch) {
while (!!navigator.next() && (!(navigator.current() instanceof FolderMatch) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) { }
} else if (element instanceof FileMatch) {
while (!!navigator.next() && (!(navigator.current() instanceof FileMatch) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) {
viewer.expand(navigator.current());
}
} else {
while (navigator.next() && (!(navigator.current() instanceof Match) || arrayContainsElementOrParent(navigator.current(), elementsToRemove))) {
viewer.expand(navigator.current());
}
}
return navigator.current();
}

Yes, this definitely makes sense. I decided to do it this way (selecting the previous) so that, when the person clicks f4 again, the editor will jump to the result after the deleted selected node. I did it this way because of my interpretation of the original issue.

The behavior I expect:
Press Ctrl+Shift+F to perform a search.
Press F4 a few times.
Edit the location of the search item, even to the point of it no longer matching the search term.
Press F4. Editor location should jump to the search item that followed the previous search item while it still existed.

If you prefer, I can also do it in the way you suggested :)

@andreamah
Copy link
Contributor

If you prefer, I can also do it in the way you suggested :)

No, I think it makes sense to progress to the next one. I think I originally said this because clicking 'x' to remove a search result went to the result before, but I think I'd accept the inconsistency with that here.

Copy link
Contributor

@andreamah andreamah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies for being on and off with replies, but it looks pretty ready to go! Just one small comment.

this.tree.expand(beforePrevious);
}

beforePrevious = navigator.previous();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Can you check the event variable for removed: true for this so that it doesn't run every time we refresh the tree?

Comment on lines +754 to +756
if (this.tree.isCollapsed(beforePrevious)) {
this.tree.expand(beforePrevious);
}
Copy link
Contributor

@andreamah andreamah Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this logic is correct.

Image from Gyazo

When you expand an element, you might want to go previous from what was after it in order to get the true previous match.

Bug steps:

  1. Collapse the node before the target search result.
  2. remove the target search result by editing it
  3. 🐛 the result goes to the node before the collapsed node, and still expands the collapsed node.

Copy link
Contributor

@andreamah andreamah Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Might also be good to test in the tree view for search.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic is more correct than what we have now, at sure, it virtually doesn't matter if the focus jumps one item up or down on deletion, important is that it doesn't jump to the first item.

Can you pls merge this PR, the current state is much worse than this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Search pane: F4 after editing should visit the next search entry
4 participants