Open buffer when trying to expand a file

Antonio Scandurra created

Change summary

zed/src/project_panel.rs | 111 +++++++++++++++++++++++++++--------------
zed/src/workspace.rs     |  13 ----
2 files changed, 75 insertions(+), 49 deletions(-)

Detailed changes

zed/src/project_panel.rs 🔗

@@ -1,6 +1,7 @@
 use crate::{
     project::{self, Project},
     theme,
+    workspace::Workspace,
     worktree::{self, Worktree},
     Settings,
 };
@@ -14,7 +15,7 @@ use gpui::{
     },
     platform::CursorStyle,
     AppContext, Element, ElementBox, Entity, ModelHandle, MutableAppContext, ReadModel, View,
-    ViewContext, WeakViewHandle,
+    ViewContext, ViewHandle, WeakViewHandle,
 };
 use postage::watch;
 use std::{
@@ -51,7 +52,7 @@ struct EntryDetails {
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct ProjectEntry {
-    pub worktree_ix: usize,
+    pub worktree_id: usize,
     pub entry_id: usize,
 }
 
@@ -66,51 +67,73 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(ProjectPanel::toggle_expanded);
     cx.add_action(ProjectPanel::select_prev);
     cx.add_action(ProjectPanel::select_next);
+    cx.add_action(ProjectPanel::open_entry);
     cx.add_bindings([
         Binding::new("right", ExpandSelectedEntry, None),
         Binding::new("left", CollapseSelectedEntry, None),
     ]);
 }
 
-pub enum Event {}
+pub enum Event {
+    OpenedEntry { worktree_id: usize, entry_id: usize },
+}
 
 impl ProjectPanel {
     pub fn new(
         project: ModelHandle<Project>,
         settings: watch::Receiver<Settings>,
-        cx: &mut ViewContext<Self>,
-    ) -> Self {
-        cx.observe(&project, |this, _, cx| {
-            this.update_visible_entries(None, cx);
-            cx.notify();
-        })
-        .detach();
-        cx.subscribe(&project, |this, _, event, cx| match event {
-            project::Event::ActiveEntryChanged(Some((worktree_id, entry_id))) => {
-                this.expand_entry(*worktree_id, *entry_id, cx);
-                this.update_visible_entries(Some((*worktree_id, *entry_id)), cx);
-                cx.notify();
-            }
-            project::Event::WorktreeRemoved(id) => {
-                this.expanded_dir_ids.remove(id);
+        cx: &mut ViewContext<Workspace>,
+    ) -> ViewHandle<Self> {
+        let project_panel = cx.add_view(|cx: &mut ViewContext<Self>| {
+            cx.observe(&project, |this, _, cx| {
                 this.update_visible_entries(None, cx);
                 cx.notify();
+            })
+            .detach();
+            cx.subscribe(&project, |this, _, event, cx| match event {
+                project::Event::ActiveEntryChanged(Some((worktree_id, entry_id))) => {
+                    this.expand_entry(*worktree_id, *entry_id, cx);
+                    this.update_visible_entries(Some((*worktree_id, *entry_id)), cx);
+                    cx.notify();
+                }
+                project::Event::WorktreeRemoved(id) => {
+                    this.expanded_dir_ids.remove(id);
+                    this.update_visible_entries(None, cx);
+                    cx.notify();
+                }
+                _ => {}
+            })
+            .detach();
+
+            let mut this = Self {
+                project: project.clone(),
+                settings,
+                list: Default::default(),
+                visible_entries: Default::default(),
+                expanded_dir_ids: Default::default(),
+                selection: None,
+                handle: cx.handle().downgrade(),
+            };
+            this.update_visible_entries(None, cx);
+            this
+        });
+        cx.subscribe(&project_panel, move |workspace, _, event, cx| match event {
+            Event::OpenedEntry {
+                worktree_id,
+                entry_id,
+            } => {
+                if let Some(worktree) = project.read(cx).worktree_for_id(*worktree_id) {
+                    if let Some(entry) = worktree.read(cx).entry_for_id(*entry_id) {
+                        workspace
+                            .open_entry((worktree.id(), entry.path.clone()), cx)
+                            .map(|t| t.detach());
+                    }
+                }
             }
-            _ => {}
         })
         .detach();
 
-        let mut this = Self {
-            project,
-            settings,
-            list: Default::default(),
-            visible_entries: Default::default(),
-            expanded_dir_ids: Default::default(),
-            selection: None,
-            handle: cx.handle().downgrade(),
-        };
-        this.update_visible_entries(None, cx);
-        this
+        project_panel
     }
 
     fn expand_selected_entry(&mut self, _: &ExpandSelectedEntry, cx: &mut ViewContext<Self>) {
@@ -132,6 +155,11 @@ impl ProjectPanel {
                     }
                 }
             } else {
+                let event = Event::OpenedEntry {
+                    worktree_id: worktree.id(),
+                    entry_id: entry.id,
+                };
+                cx.emit(event);
             }
         }
     }
@@ -169,10 +197,10 @@ impl ProjectPanel {
 
     fn toggle_expanded(&mut self, action: &ToggleExpanded, cx: &mut ViewContext<Self>) {
         let ProjectEntry {
-            worktree_ix,
+            worktree_id,
             entry_id,
         } = action.0;
-        let worktree_id = self.project.read(cx).worktrees()[worktree_ix].id();
+
         if let Some(expanded_dir_ids) = self.expanded_dir_ids.get_mut(&worktree_id) {
             match expanded_dir_ids.binary_search(&entry_id) {
                 Ok(ix) => {
@@ -203,6 +231,13 @@ impl ProjectPanel {
         }
     }
 
+    fn open_entry(&mut self, action: &Open, cx: &mut ViewContext<Self>) {
+        cx.emit(Event::OpenedEntry {
+            worktree_id: action.0.worktree_id,
+            entry_id: action.0.entry_id,
+        });
+    }
+
     fn select_next(&mut self, _: &SelectNext, cx: &mut ViewContext<Self>) {
         if let Some(selection) = self.selection {
             let next_ix = selection.index + 1;
@@ -411,7 +446,7 @@ impl ProjectPanel {
                         }),
                     };
                     let entry = ProjectEntry {
-                        worktree_ix,
+                        worktree_id: worktree.id(),
                         entry_id: entry.id,
                     };
                     callback(entry, details, cx);
@@ -429,7 +464,7 @@ impl ProjectPanel {
     ) -> ElementBox {
         let is_dir = details.is_dir;
         MouseEventHandler::new::<Self, _, _, _>(
-            (entry.worktree_ix, entry.entry_id),
+            (entry.worktree_id, entry.entry_id),
             cx,
             |state, _| {
                 let style = if details.is_selected {
@@ -568,7 +603,8 @@ mod tests {
             .read_with(&cx, |t, _| t.as_local().unwrap().scan_complete())
             .await;
 
-        let (_, panel) = cx.add_window(|cx| ProjectPanel::new(project, settings, cx));
+        let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
+        let panel = workspace.update(&mut cx, |_, cx| ProjectPanel::new(project, settings, cx));
         assert_eq!(
             visible_entry_details(&panel, 0..50, &mut cx),
             &[
@@ -742,14 +778,13 @@ mod tests {
         ) {
             let path = path.as_ref();
             panel.update(cx, |panel, cx| {
-                for (worktree_ix, worktree) in panel.project.read(cx).worktrees().iter().enumerate()
-                {
+                for worktree in panel.project.read(cx).worktrees() {
                     let worktree = worktree.read(cx);
                     if let Ok(relative_path) = path.strip_prefix(worktree.root_name()) {
                         let entry_id = worktree.entry_for_path(relative_path).unwrap().id;
                         panel.toggle_expanded(
                             &ToggleExpanded(ProjectEntry {
-                                worktree_ix,
+                                worktree_id: worktree.id(),
                                 entry_id,
                             }),
                             cx,

zed/src/workspace.rs 🔗

@@ -8,7 +8,7 @@ use crate::{
     fs::Fs,
     people_panel::{JoinWorktree, LeaveWorktree, PeoplePanel, ShareWorktree, UnshareWorktree},
     project::Project,
-    project_panel::{self, ProjectPanel},
+    project_panel::ProjectPanel,
     rpc,
     settings::Settings,
     user,
@@ -54,14 +54,6 @@ pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(Workspace::save_active_item);
     cx.add_action(Workspace::debug_elements);
     cx.add_action(Workspace::open_new_file);
-    cx.add_action(|this: &mut Workspace, action: &project_panel::Open, cx| {
-        if let Some(worktree) = this.worktrees(cx).get(action.0.worktree_ix) {
-            if let Some(entry) = worktree.read(cx).entry_for_id(action.0.entry_id) {
-                this.open_entry((worktree.id(), entry.path.clone()), cx)
-                    .map(|task| task.detach());
-            }
-        }
-    });
     cx.add_action(Workspace::toggle_sidebar_item);
     cx.add_action(Workspace::share_worktree);
     cx.add_action(Workspace::unshare_worktree);
@@ -386,8 +378,7 @@ impl Workspace {
         let mut left_sidebar = Sidebar::new(Side::Left);
         left_sidebar.add_item(
             "icons/folder-tree-16.svg",
-            cx.add_view(|cx| ProjectPanel::new(project.clone(), app_state.settings.clone(), cx))
-                .into(),
+            ProjectPanel::new(project.clone(), app_state.settings.clone(), cx).into(),
         );
 
         let mut right_sidebar = Sidebar::new(Side::Right);