diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index be60041277e97289bc7a3fdf43794dc3a72047e4..64e66939c407a9092d495d17bcd85323423f24c5 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -544,17 +544,28 @@ impl DisplayMap { let all_blocks: Vec<_> = self.block_map.blocks_raw().map(Clone::clone).collect(); companion_display_map.update(cx, |companion_display_map, cx| { + // Sync folded buffers from RHS to LHS. Also clean up stale + // entries: the block map doesn't remove buffers from + // `folded_buffers` when they leave the multibuffer, so we + // unfold any RHS buffers whose companion mapping is missing. + let mut buffers_to_unfold = Vec::new(); for my_buffer in self.folded_buffers() { - let their_buffer = companion - .read(cx) - .rhs_buffer_to_lhs_buffer - .get(my_buffer) - .unwrap(); + let their_buffer = companion.read(cx).rhs_buffer_to_lhs_buffer.get(my_buffer); + + let Some(their_buffer) = their_buffer else { + buffers_to_unfold.push(*my_buffer); + continue; + }; + companion_display_map .block_map .folded_buffers .insert(*their_buffer); } + for buffer_id in buffers_to_unfold { + self.block_map.folded_buffers.remove(&buffer_id); + } + for block in all_blocks { let Some(their_block) = block_map::balancing_block( &block.properties(), diff --git a/crates/editor/src/split.rs b/crates/editor/src/split.rs index 1dd382089605b77b19c218eb63b19ea1875bd911..908438319263fbfe0db6842b2ee848aa418be1a7 100644 --- a/crates/editor/src/split.rs +++ b/crates/editor/src/split.rs @@ -5755,4 +5755,106 @@ mod tests { &mut cx, ); } + + #[gpui::test] + async fn test_split_after_removing_folded_buffer(cx: &mut gpui::TestAppContext) { + use rope::Point; + use unindent::Unindent as _; + + let (editor, mut cx) = init_test(cx, SoftWrap::None, DiffViewStyle::Unified).await; + + let base_text_a = " + aaa + bbb + ccc + " + .unindent(); + let current_text_a = " + aaa + bbb modified + ccc + " + .unindent(); + + let base_text_b = " + xxx + yyy + zzz + " + .unindent(); + let current_text_b = " + xxx + yyy modified + zzz + " + .unindent(); + + let (buffer_a, diff_a) = buffer_with_diff(&base_text_a, ¤t_text_a, &mut cx); + let (buffer_b, diff_b) = buffer_with_diff(&base_text_b, ¤t_text_b, &mut cx); + + let path_a = cx.read(|cx| PathKey::for_buffer(&buffer_a, cx)); + let path_b = cx.read(|cx| PathKey::for_buffer(&buffer_b, cx)); + + editor.update(cx, |editor, cx| { + editor.set_excerpts_for_path( + path_a.clone(), + buffer_a.clone(), + vec![Point::new(0, 0)..buffer_a.read(cx).max_point()], + 0, + diff_a.clone(), + cx, + ); + editor.set_excerpts_for_path( + path_b.clone(), + buffer_b.clone(), + vec![Point::new(0, 0)..buffer_b.read(cx).max_point()], + 0, + diff_b.clone(), + cx, + ); + }); + + cx.run_until_parked(); + + let buffer_a_id = buffer_a.read_with(cx, |buffer, _| buffer.remote_id()); + editor.update(cx, |editor, cx| { + editor.rhs_editor().update(cx, |right_editor, cx| { + right_editor.fold_buffer(buffer_a_id, cx) + }); + }); + + cx.run_until_parked(); + + editor.update(cx, |editor, cx| { + editor.remove_excerpts_for_path(path_a.clone(), cx); + }); + cx.run_until_parked(); + + editor.update_in(cx, |editor, window, cx| editor.split(window, cx)); + cx.run_until_parked(); + + editor.update(cx, |editor, cx| { + editor.set_excerpts_for_path( + path_a.clone(), + buffer_a.clone(), + vec![Point::new(0, 0)..buffer_a.read(cx).max_point()], + 0, + diff_a.clone(), + cx, + ); + assert!( + !editor + .lhs_editor() + .unwrap() + .read(cx) + .is_buffer_folded(buffer_a_id, cx) + ); + assert!( + !editor + .rhs_editor() + .read(cx) + .is_buffer_folded(buffer_a_id, cx) + ); + }); + } }