editor: Unfold buffers with selections on edit + Remove selections on buffer fold (#37953)
Closes #36376 Problem: Multi-cursor edits/selections in multi-buffers view were jumping to incorrect locations after toggling buffer folds. When users created multiple selections across different buffers in a multi-buffer view (like project search results) and then folded one of the buffers, subsequent text insertion would either: 1. Insert text at wrong locations (like at the top of the first unfolded buffer) 2. Replace the entire content in some buffers instead of inserting at the intended cursor positions 3. Create orphaned selections that caused corruption in the editing experience The issue seems to happen because when a buffer gets folded in a multi-buffer view, the existing selections associated with that buffer become invalid anchor points. Solution: 1. Selection Cleanup on Buffer Folding - Added `remove_selections_from_buffer()` method that filters out all selections from a buffer when it gets folded - This prevents invalid selections from corrupting subsequent editing operations - Includes edge case handling: if all selections are removed (all buffers folded), it creates a default selection at the start of the first buffer to prevent panics 2. Unfolding buffers before editing - Added `unfold_buffers_with_selections()` call in `handle_input()` ensures buffers with active selections are automatically unfolded before editing - This helps in fixing an edge case (covered in the tests) where, if you fold all buffers in a multi-buffer view, and try to insert text in a selection, it gets unfolded before the edit happens. Without this, the inserted text would override the entire buffer content. - If we don't care about this edge case, we could remove this method. I find it ok to add since we already trigger buffer unfolding after edits with `Event::ExcerptsEdited`. Release Notes: - Fixed multi-cursor edits jumping to incorrect locations after toggling buffer folds in multi-buffer views (e.g, project search) - Multi-cursor selections now properly handle buffer folding/unfolding operations - Text insertion no longer occurs at the wrong positions when buffers are folded during multi-cursor editing - Eliminated content replacement bugs where entire buffer contents were incorrectly overwritten - Added safe fallback behavior when all buffers in a multi-buffer view are folded --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
This commit is contained in:
co-authored by
Smit Barmase
parent
1c4bb60209
commit
dc372e8a84
@@ -3449,6 +3449,21 @@ impl Editor {
|
||||
Subscription::join(other_subscription, this_subscription)
|
||||
}
|
||||
|
||||
fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
|
||||
if self.buffer().read(cx).is_singleton() {
|
||||
return;
|
||||
}
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let buffer_ids: HashSet<BufferId> = self
|
||||
.selections
|
||||
.disjoint_anchor_ranges()
|
||||
.flat_map(|range| snapshot.buffer_ids_for_range(range))
|
||||
.collect();
|
||||
for buffer_id in buffer_ids {
|
||||
self.unfold_buffer(buffer_id, cx);
|
||||
}
|
||||
}
|
||||
|
||||
/// Changes selections using the provided mutation function. Changes to `self.selections` occur
|
||||
/// immediately, but when run within `transact` or `with_selection_effects_deferred` other
|
||||
/// effects of selection change occur at the end of the transaction.
|
||||
@@ -4190,6 +4205,8 @@ impl Editor {
|
||||
|
||||
self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
|
||||
|
||||
self.unfold_buffers_with_selections(cx);
|
||||
|
||||
let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
|
||||
let mut bracket_inserted = false;
|
||||
let mut edits = Vec::new();
|
||||
@@ -18879,10 +18896,17 @@ impl Editor {
|
||||
if self.buffer().read(cx).is_singleton() || self.is_buffer_folded(buffer_id, cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
|
||||
self.display_map.update(cx, |display_map, cx| {
|
||||
display_map.fold_buffers([buffer_id], cx)
|
||||
});
|
||||
|
||||
let snapshot = self.display_snapshot(cx);
|
||||
self.selections.change_with(&snapshot, |selections| {
|
||||
selections.remove_selections_from_buffer(buffer_id);
|
||||
});
|
||||
|
||||
cx.emit(EditorEvent::BufferFoldToggled {
|
||||
ids: folded_excerpts.iter().map(|&(id, _)| id).collect(),
|
||||
folded: true,
|
||||
|
||||
Reference in New Issue
Block a user