@@ -24145,6 +24145,7 @@ impl Editor {
self.display_map.update(cx, |display_map, cx| {
display_map.invalidate_semantic_highlights(*buffer_id);
display_map.clear_lsp_folding_ranges(*buffer_id, cx);
+ display_map.clear_folded_buffer(*buffer_id);
});
}
jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
@@ -24308,6 +24308,77 @@ async fn test_folding_buffers(cx: &mut TestAppContext) {
);
}
+#[gpui::test]
+async fn test_folded_buffers_cleared_on_excerpts_removed(cx: &mut TestAppContext) {
+ init_test(cx, |_| {});
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(
+ path!("/root"),
+ json!({
+ "file_a.txt": "File A\nFile A\nFile A",
+ "file_b.txt": "File B\nFile B\nFile B",
+ }),
+ )
+ .await;
+
+ let project = Project::test(fs, [path!("/root").as_ref()], cx).await;
+ let window = cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
+ let cx = &mut VisualTestContext::from_window(*window, cx);
+ let worktree = project.update(cx, |project, cx| {
+ let mut worktrees = project.worktrees(cx).collect::<Vec<_>>();
+ assert_eq!(worktrees.len(), 1);
+ worktrees.pop().unwrap()
+ });
+ let worktree_id = worktree.update(cx, |worktree, _| worktree.id());
+
+ let buffer_a = project
+ .update(cx, |project, cx| {
+ project.open_buffer((worktree_id, rel_path("file_a.txt")), cx)
+ })
+ .await
+ .unwrap();
+ let buffer_b = project
+ .update(cx, |project, cx| {
+ project.open_buffer((worktree_id, rel_path("file_b.txt")), cx)
+ })
+ .await
+ .unwrap();
+
+ let multi_buffer = cx.new(|cx| {
+ let mut multi_buffer = MultiBuffer::new(ReadWrite);
+ let range_a = Point::new(0, 0)..Point::new(2, 4);
+ let range_b = Point::new(0, 0)..Point::new(2, 4);
+
+ multi_buffer.set_excerpts_for_path(PathKey::sorted(0), buffer_a.clone(), [range_a], 0, cx);
+ multi_buffer.set_excerpts_for_path(PathKey::sorted(1), buffer_b.clone(), [range_b], 0, cx);
+ multi_buffer
+ });
+
+ let editor = cx.new_window_entity(|window, cx| {
+ Editor::new(
+ EditorMode::full(),
+ multi_buffer.clone(),
+ Some(project.clone()),
+ window,
+ cx,
+ )
+ });
+
+ editor.update(cx, |editor, cx| {
+ editor.fold_buffer(buffer_a.read(cx).remote_id(), cx);
+ });
+ assert!(editor.update(cx, |editor, cx| editor.has_any_buffer_folded(cx)));
+
+ // When the excerpts for `buffer_a` are removed, a
+ // `multi_buffer::Event::ExcerptsRemoved` event is emitted, which should be
+ // picked up by the editor and update the display map accordingly.
+ multi_buffer.update(cx, |multi_buffer, cx| {
+ multi_buffer.remove_excerpts_for_path(PathKey::sorted(0), cx)
+ });
+ assert!(!editor.update(cx, |editor, cx| editor.has_any_buffer_folded(cx)));
+}
+
#[gpui::test]
async fn test_folding_buffers_with_one_excerpt(cx: &mut TestAppContext) {
init_test(cx, |_| {});
@@ -105,6 +105,8 @@ pub enum Event {
},
ExcerptsRemoved {
ids: Vec<ExcerptId>,
+ /// Contains only buffer IDs for which all excerpts have been removed.
+ /// Buffers that still have remaining excerpts are never included.
removed_buffer_ids: Vec<BufferId>,
},
ExcerptsExpanded {