editor: Fix line selection disappears when the cursor goes off screen - #60054
Conversation
ChristopherBiscardi
left a comment
There was a problem hiding this comment.
What is the process for reproducing this? Does it rely on using a specific vim-mode sequence?
I can confirm this behavior when single-clicking into a soft-wrapped paragraph and scrolling the cursor out of view, but this is not the behavior that this PR targets, nor does it seem to be what is happening in the screen recordings.
|
yes you do need to be in vim mode to see the behavior I was originally describing so for replicating you can use the same setup you are using to see that single click behavior but then just be in vim mode and do The the solution to that to me seems like to remove the I think a) makes the most sense, and maybe the solution is to make a new function, like |
|
refactored the |
…zed-industries#60054) # Objective When you make a line selection in a row that is long enough to multiple lines long while wrapped the selection box will disappear when the cursor (or just origin of the line selection goes off screen). ## Solution The when you are in line selection mode the `SelectionsCollection` just enables `line_mode`, instead of storing the whole ranges of those line selections, so the Anchor of the selection is a single point. `disjoint_in_range` filters all the disjoint selections of the collection to fit inside some range, this is used to render the selection boxes on screen. `disjoint_in_range` had no special case for `line_mode` causing it to filter on the point instead of the bounds of the selection. My fix is too add a case for `line_mode` that changes the filtering `Anchor` -> `Point` and then only filters on the row. Then use the proper bounds of the selection with that: ```rust let (start_ix, end_ix) = if self.line_mode { let start_row = range.start.to_point(buffer).row; let end_row = range.end.to_point(buffer).row; let start_ix = self .disjoint .partition_point(|probe| probe.end.to_point(buffer).row < start_row); let end_ix = self .disjoint .partition_point(|probe| probe.start.to_point(buffer).row <= end_row); (start_ix, end_ix) } else { ... ``` ## Testing Before: https://github.com/user-attachments/assets/a443de39-53d7-4ee4-b3af-d3be99ca1fcf After: https://github.com/user-attachments/assets/18c1c7ef-45cc-4dc8-9a8b-241252c376ab I also added some tests `disjoint_in_range_line_mode_matches_whole_row`, being the one that really tests this behavior. the other two are just for `disjoint_in_range` I am using macOS 27.0 Beta (26A5368g), but I noticed this bug before upgrading. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - editor: Fixed bug where selection boxes wouldn't render when the cursor was offscreen.
…zed-industries#60054) # Objective When you make a line selection in a row that is long enough to multiple lines long while wrapped the selection box will disappear when the cursor (or just origin of the line selection goes off screen). ## Solution The when you are in line selection mode the `SelectionsCollection` just enables `line_mode`, instead of storing the whole ranges of those line selections, so the Anchor of the selection is a single point. `disjoint_in_range` filters all the disjoint selections of the collection to fit inside some range, this is used to render the selection boxes on screen. `disjoint_in_range` had no special case for `line_mode` causing it to filter on the point instead of the bounds of the selection. My fix is too add a case for `line_mode` that changes the filtering `Anchor` -> `Point` and then only filters on the row. Then use the proper bounds of the selection with that: ```rust let (start_ix, end_ix) = if self.line_mode { let start_row = range.start.to_point(buffer).row; let end_row = range.end.to_point(buffer).row; let start_ix = self .disjoint .partition_point(|probe| probe.end.to_point(buffer).row < start_row); let end_ix = self .disjoint .partition_point(|probe| probe.start.to_point(buffer).row <= end_row); (start_ix, end_ix) } else { ... ``` ## Testing Before: https://github.com/user-attachments/assets/a443de39-53d7-4ee4-b3af-d3be99ca1fcf After: https://github.com/user-attachments/assets/18c1c7ef-45cc-4dc8-9a8b-241252c376ab I also added some tests `disjoint_in_range_line_mode_matches_whole_row`, being the one that really tests this behavior. the other two are just for `disjoint_in_range` I am using macOS 27.0 Beta (26A5368g), but I noticed this bug before upgrading. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - editor: Fixed bug where selection boxes wouldn't render when the cursor was offscreen.
Objective
When you make a line selection in a row that is long enough to multiple lines long while wrapped the selection box will disappear when the cursor (or just origin of the line selection goes off screen).
Solution
The when you are in line selection mode the
SelectionsCollectionjust enablesline_mode, instead of storing the whole ranges of those line selections, so the Anchor of the selection is a single point.disjoint_in_rangefilters all the disjoint selections of the collection to fit inside some range, this is used to render the selection boxes on screen.disjoint_in_rangehad no special case forline_modecausing it to filter on the point instead of the bounds of the selection.My fix is too add a case for
line_modethat changes the filteringAnchor->Pointand then only filters on the row. Then use the proper bounds of the selection with that:Testing
Before:
BEFORE.mov
After:
AFTER.mov
I also added some tests
disjoint_in_range_line_mode_matches_whole_row, being the one that really tests this behavior. the other two are just fordisjoint_in_rangeI am using macOS 27.0 Beta (26A5368g), but I noticed this bug before upgrading.
Self-Review Checklist:
Release Notes: