Fix expand/collapse all button for splittable editor (#50859)

Dino and Tom Houlé created

The "Expand All Files"/"Collapse All Files" button in `BufferSearchBar`
was broken for `SplittableEditor`, which is used in the project diff
view. It was happening because `ProjectDiff::as_searchable` returns an
handle to the `SplittableEditor`, which the search bar implementation
then tries to downcast to an `Editor`, which the `SplittableEditor` did
not support, so both the expand/collapse all buttons, as well as the
collapse state were broken.

Unfortunately this was accidentally introduced in
https://github.com/zed-industries/zed/pull/48773 , so this Pull Request
updates the `Item` implementation for `SplittableEditor` in order for it
to be able to act as an `Editor`.

Release Notes:

- Fix the "Expand All Files"/"Collapse All Files" button in the project
diff view

---------

Co-authored-by: Tom Houlé <tom@tomhoule.com>

Change summary

crates/editor/src/split.rs | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)

Detailed changes

crates/editor/src/split.rs 🔗

@@ -1857,6 +1857,21 @@ impl Item for SplittableEditor {
     fn pixel_position_of_cursor(&self, cx: &App) -> Option<gpui::Point<gpui::Pixels>> {
         self.focused_editor().read(cx).pixel_position_of_cursor(cx)
     }
+
+    fn act_as_type<'a>(
+        &'a self,
+        type_id: std::any::TypeId,
+        self_handle: &'a Entity<Self>,
+        _: &'a App,
+    ) -> Option<gpui::AnyEntity> {
+        if type_id == std::any::TypeId::of::<Self>() {
+            Some(self_handle.clone().into())
+        } else if type_id == std::any::TypeId::of::<Editor>() {
+            Some(self.rhs_editor.clone().into())
+        } else {
+            None
+        }
+    }
 }
 
 impl SearchableItem for SplittableEditor {
@@ -2064,7 +2079,7 @@ impl Render for SplittableEditor {
 
 #[cfg(test)]
 mod tests {
-    use std::sync::Arc;
+    use std::{any::TypeId, sync::Arc};
 
     use buffer_diff::BufferDiff;
     use collections::{HashMap, HashSet};
@@ -2080,14 +2095,14 @@ mod tests {
     use settings::{DiffViewStyle, SettingsStore};
     use ui::{VisualContext as _, div, px};
     use util::rel_path::rel_path;
-    use workspace::MultiWorkspace;
+    use workspace::{Item, MultiWorkspace};
 
-    use crate::SplittableEditor;
     use crate::display_map::{
         BlockPlacement, BlockProperties, BlockStyle, Crease, FoldPlaceholder,
     };
     use crate::inlays::Inlay;
     use crate::test::{editor_content_with_blocks_and_width, set_block_content_for_tests};
+    use crate::{Editor, SplittableEditor};
     use multi_buffer::MultiBufferOffset;
 
     async fn init_test(
@@ -6025,4 +6040,17 @@ mod tests {
 
         cx.run_until_parked();
     }
+
+    #[gpui::test]
+    async fn test_act_as_type(cx: &mut gpui::TestAppContext) {
+        let (splittable_editor, cx) = init_test(cx, SoftWrap::None, DiffViewStyle::Split).await;
+        let editor = splittable_editor.read_with(cx, |editor, cx| {
+            editor.act_as_type(TypeId::of::<Editor>(), &splittable_editor, cx)
+        });
+
+        assert!(
+            editor.is_some(),
+            "SplittableEditor should be able to act as Editor"
+        );
+    }
 }