Introduce ProjectPath and ProjectEntry structs

Nathan Sobo created

These replace tuples of (usize, Arc<Path>) and (usize, usize) respectively.

Change summary

fuzzy/src/lib.rs          |   6 
server/src/rpc.rs         |  11 ++
zed/src/editor.rs         |  18 +++--
zed/src/file_finder.rs    |  35 +++++------
zed/src/project.rs        |  35 +++++++---
zed/src/project_panel.rs  |  21 +++--
zed/src/workspace.rs      | 124 +++++++++++++++++++++++-----------------
zed/src/workspace/pane.rs |  10 +-
zed/src/worktree.rs       |  24 ++++---
9 files changed, 163 insertions(+), 121 deletions(-)

Detailed changes

fuzzy/src/lib.rs 🔗

@@ -47,7 +47,7 @@ pub struct PathMatchCandidate<'a> {
 pub struct PathMatch {
     pub score: f64,
     pub positions: Vec<usize>,
-    pub tree_id: usize,
+    pub worktree_id: usize,
     pub path: Arc<Path>,
     pub path_prefix: Arc<str>,
 }
@@ -147,7 +147,7 @@ impl Ord for PathMatch {
         self.score
             .partial_cmp(&other.score)
             .unwrap_or(Ordering::Equal)
-            .then_with(|| self.tree_id.cmp(&other.tree_id))
+            .then_with(|| self.worktree_id.cmp(&other.worktree_id))
             .then_with(|| Arc::as_ptr(&self.path).cmp(&Arc::as_ptr(&other.path)))
     }
 }
@@ -215,7 +215,7 @@ impl<'a> Matcher<'a> {
             cancel_flag,
             |candidate, score| PathMatch {
                 score,
-                tree_id,
+                worktree_id: tree_id,
                 positions: Vec::new(),
                 path: candidate.path.clone(),
                 path_prefix: path_prefix.clone(),

server/src/rpc.rs 🔗

@@ -980,6 +980,7 @@ mod tests {
         fs::{FakeFs, Fs as _},
         language::LanguageRegistry,
         people_panel::JoinWorktree,
+        project::ProjectPath,
         rpc::{self, Client, Credentials, EstablishConnectionError},
         settings,
         test::FakeHttpClient,
@@ -1166,8 +1167,14 @@ mod tests {
             workspace.worktrees(cx).first().unwrap().id()
         });
         workspace_b
-            .update(&mut cx_b, |worktree, cx| {
-                worktree.open_entry((local_worktree_id_b, Path::new("a.txt").into()), cx)
+            .update(&mut cx_b, |workspace, cx| {
+                workspace.open_entry(
+                    ProjectPath {
+                        worktree_id: local_worktree_id_b,
+                        path: Path::new("a.txt").into(),
+                    },
+                    cx,
+                )
             })
             .unwrap()
             .await;

zed/src/editor.rs 🔗

@@ -5,6 +5,7 @@ pub mod movement;
 
 use crate::{
     language::Language,
+    project::ProjectPath,
     settings::Settings,
     theme::Theme,
     time::ReplicaId,
@@ -2589,8 +2590,11 @@ impl workspace::Item for Buffer {
         )
     }
 
-    fn worktree_id_and_path(&self) -> Option<(usize, Arc<Path>)> {
-        self.file().map(|f| (f.worktree_id(), f.path().clone()))
+    fn project_path(&self) -> Option<ProjectPath> {
+        self.file().map(|f| ProjectPath {
+            worktree_id: f.worktree_id(),
+            path: f.path().clone(),
+        })
     }
 }
 
@@ -2623,11 +2627,11 @@ impl workspace::ItemView for Editor {
         }
     }
 
-    fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)> {
-        self.buffer
-            .read(cx)
-            .file()
-            .map(|file| (file.worktree_id(), file.path().clone()))
+    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
+        self.buffer.read(cx).file().map(|file| ProjectPath {
+            worktree_id: file.worktree_id(),
+            path: file.path().clone(),
+        })
     }
 
     fn clone_on_split(&self, cx: &mut ViewContext<Self>) -> Option<Self>

zed/src/file_finder.rs 🔗

@@ -1,7 +1,7 @@
 use crate::{
     editor::{self, Editor},
     fuzzy::PathMatch,
-    project::Project,
+    project::{Project, ProjectPath},
     settings::Settings,
     util,
     workspace::Workspace,
@@ -44,13 +44,7 @@ pub struct FileFinder {
 
 action!(Toggle);
 action!(Confirm);
-action!(Select, Entry);
-
-#[derive(Clone)]
-pub struct Entry {
-    worktree_id: usize,
-    path: Arc<Path>,
-}
+action!(Select, ProjectPath);
 
 pub fn init(cx: &mut MutableAppContext) {
     cx.add_action(FileFinder::toggle);
@@ -67,7 +61,7 @@ pub fn init(cx: &mut MutableAppContext) {
 }
 
 pub enum Event {
-    Selected(usize, Arc<Path>),
+    Selected(ProjectPath),
     Dismissed,
 }
 
@@ -203,8 +197,8 @@ impl FileFinder {
         )
         .with_style(style.container);
 
-        let action = Select(Entry {
-            worktree_id: path_match.tree_id,
+        let action = Select(ProjectPath {
+            worktree_id: path_match.worktree_id,
             path: path_match.path.clone(),
         });
         EventHandler::new(container.boxed())
@@ -256,9 +250,9 @@ impl FileFinder {
         cx: &mut ViewContext<Workspace>,
     ) {
         match event {
-            Event::Selected(tree_id, path) => {
+            Event::Selected(project_path) => {
                 workspace
-                    .open_entry((*tree_id, path.clone()), cx)
+                    .open_entry(project_path.clone(), cx)
                     .map(|d| d.detach());
                 workspace.dismiss_modal(cx);
             }
@@ -338,7 +332,7 @@ impl FileFinder {
     fn selected_index(&self) -> usize {
         if let Some(selected) = self.selected.as_ref() {
             for (ix, path_match) in self.matches.iter().enumerate() {
-                if (path_match.tree_id, path_match.path.as_ref())
+                if (path_match.worktree_id, path_match.path.as_ref())
                     == (selected.0, selected.1.as_ref())
                 {
                     return ix;
@@ -353,7 +347,7 @@ impl FileFinder {
         if selected_index > 0 {
             selected_index -= 1;
             let mat = &self.matches[selected_index];
-            self.selected = Some((mat.tree_id, mat.path.clone()));
+            self.selected = Some((mat.worktree_id, mat.path.clone()));
         }
         self.list_state.scroll_to(selected_index);
         cx.notify();
@@ -364,7 +358,7 @@ impl FileFinder {
         if selected_index + 1 < self.matches.len() {
             selected_index += 1;
             let mat = &self.matches[selected_index];
-            self.selected = Some((mat.tree_id, mat.path.clone()));
+            self.selected = Some((mat.worktree_id, mat.path.clone()));
         }
         self.list_state.scroll_to(selected_index);
         cx.notify();
@@ -372,12 +366,15 @@ impl FileFinder {
 
     fn confirm(&mut self, _: &Confirm, cx: &mut ViewContext<Self>) {
         if let Some(m) = self.matches.get(self.selected_index()) {
-            cx.emit(Event::Selected(m.tree_id, m.path.clone()));
+            cx.emit(Event::Selected(ProjectPath {
+                worktree_id: m.worktree_id,
+                path: m.path.clone(),
+            }));
         }
     }
 
-    fn select(&mut self, Select(entry): &Select, cx: &mut ViewContext<Self>) {
-        cx.emit(Event::Selected(entry.worktree_id, entry.path.clone()));
+    fn select(&mut self, Select(project_path): &Select, cx: &mut ViewContext<Self>) {
+        cx.emit(Event::Selected(project_path.clone()));
     }
 
     #[must_use]

zed/src/project.rs 🔗

@@ -17,17 +17,29 @@ use std::{
 
 pub struct Project {
     worktrees: Vec<ModelHandle<Worktree>>,
-    active_entry: Option<(usize, usize)>,
+    active_entry: Option<ProjectEntry>,
     languages: Arc<LanguageRegistry>,
     rpc: Arc<Client>,
     fs: Arc<dyn Fs>,
 }
 
 pub enum Event {
-    ActiveEntryChanged(Option<(usize, usize)>),
+    ActiveEntryChanged(Option<ProjectEntry>),
     WorktreeRemoved(usize),
 }
 
+#[derive(Clone, Debug, Eq, PartialEq, Hash)]
+pub struct ProjectPath {
+    pub worktree_id: usize,
+    pub path: Arc<Path>,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct ProjectEntry {
+    pub worktree_id: usize,
+    pub entry_id: usize,
+}
+
 impl Project {
     pub fn new(app_state: &AppState) -> Self {
         Self {
@@ -99,15 +111,14 @@ impl Project {
         cx.notify();
     }
 
-    pub fn set_active_entry(
-        &mut self,
-        entry: Option<(usize, Arc<Path>)>,
-        cx: &mut ModelContext<Self>,
-    ) {
-        let new_active_entry = entry.and_then(|(worktree_id, path)| {
-            let worktree = self.worktree_for_id(worktree_id)?;
-            let entry = worktree.read(cx).entry_for_path(path)?;
-            Some((worktree_id, entry.id))
+    pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
+        let new_active_entry = entry.and_then(|project_path| {
+            let worktree = self.worktree_for_id(project_path.worktree_id)?;
+            let entry = worktree.read(cx).entry_for_path(project_path.path)?;
+            Some(ProjectEntry {
+                worktree_id: project_path.worktree_id,
+                entry_id: entry.id,
+            })
         });
         if new_active_entry != self.active_entry {
             self.active_entry = new_active_entry;
@@ -115,7 +126,7 @@ impl Project {
         }
     }
 
-    pub fn active_entry(&self) -> Option<(usize, usize)> {
+    pub fn active_entry(&self) -> Option<ProjectEntry> {
         self.active_entry
     }
 

zed/src/project_panel.rs 🔗

@@ -1,5 +1,5 @@
 use crate::{
-    project::{self, Project},
+    project::{self, Project, ProjectEntry, ProjectPath},
     theme,
     workspace::Workspace,
     worktree::{self, Worktree},
@@ -53,12 +53,6 @@ struct EntryDetails {
     is_selected: bool,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct ProjectEntry {
-    pub worktree_id: usize,
-    pub entry_id: usize,
-}
-
 action!(ExpandSelectedEntry);
 action!(CollapseSelectedEntry);
 action!(ToggleExpanded, ProjectEntry);
@@ -94,7 +88,10 @@ impl ProjectPanel {
             })
             .detach();
             cx.subscribe(&project, |this, _, event, cx| match event {
-                project::Event::ActiveEntryChanged(Some((worktree_id, entry_id))) => {
+                project::Event::ActiveEntryChanged(Some(ProjectEntry {
+                    worktree_id,
+                    entry_id,
+                })) => {
                     this.expand_entry(*worktree_id, *entry_id, cx);
                     this.update_visible_entries(Some((*worktree_id, *entry_id)), cx);
                     this.autoscroll();
@@ -129,7 +126,13 @@ impl ProjectPanel {
                 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)
+                            .open_entry(
+                                ProjectPath {
+                                    worktree_id: worktree.id(),
+                                    path: entry.path.clone(),
+                                },
+                                cx,
+                            )
                             .map(|t| t.detach());
                     }
                 }

zed/src/workspace.rs 🔗

@@ -7,7 +7,7 @@ use crate::{
     editor::Buffer,
     fs::Fs,
     people_panel::{JoinWorktree, LeaveWorktree, PeoplePanel, ShareWorktree, UnshareWorktree},
-    project::Project,
+    project::{Project, ProjectPath},
     project_panel::ProjectPanel,
     rpc,
     settings::Settings,
@@ -164,12 +164,12 @@ pub trait Item: Entity + Sized {
         cx: &mut ViewContext<Self::View>,
     ) -> Self::View;
 
-    fn worktree_id_and_path(&self) -> Option<(usize, Arc<Path>)>;
+    fn project_path(&self) -> Option<ProjectPath>;
 }
 
 pub trait ItemView: View {
     fn title(&self, cx: &AppContext) -> String;
-    fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)>;
+    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
     fn clone_on_split(&self, _: &mut ViewContext<Self>) -> Option<Self>
     where
         Self: Sized,
@@ -213,12 +213,12 @@ pub trait WeakItemHandle {
         cx: &mut MutableAppContext,
     ) -> Option<Box<dyn ItemViewHandle>>;
     fn alive(&self, cx: &AppContext) -> bool;
-    fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)>;
+    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
 }
 
 pub trait ItemViewHandle {
     fn title(&self, cx: &AppContext) -> String;
-    fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)>;
+    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
     fn boxed_clone(&self) -> Box<dyn ItemViewHandle>;
     fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option<Box<dyn ItemViewHandle>>;
     fn set_parent_pane(&self, pane: &ViewHandle<Pane>, cx: &mut MutableAppContext);
@@ -265,9 +265,8 @@ impl<T: Item> WeakItemHandle for WeakModelHandle<T> {
         self.upgrade(cx).is_some()
     }
 
-    fn worktree_id_and_path(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)> {
-        self.upgrade(cx)
-            .and_then(|h| h.read(cx).worktree_id_and_path())
+    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
+        self.upgrade(cx).and_then(|h| h.read(cx).project_path())
     }
 }
 
@@ -276,8 +275,8 @@ impl<T: ItemView> ItemViewHandle for ViewHandle<T> {
         self.read(cx).title(cx)
     }
 
-    fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc<Path>)> {
-        self.read(cx).worktree_id_and_path(cx)
+    fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
+        self.read(cx).project_path(cx)
     }
 
     fn boxed_clone(&self) -> Box<dyn ItemViewHandle> {
@@ -368,7 +367,7 @@ pub struct Workspace {
     project: ModelHandle<Project>,
     items: Vec<Box<dyn WeakItemHandle>>,
     loading_items: HashMap<
-        (usize, Arc<Path>),
+        ProjectPath,
         postage::watch::Receiver<Option<Result<Box<dyn ItemHandle>, Arc<anyhow::Error>>>>,
     >,
     _observe_current_user: Task<()>,
@@ -382,9 +381,9 @@ impl Workspace {
         let pane = cx.add_view(|_| Pane::new(app_state.settings.clone()));
         let pane_id = pane.id();
         cx.observe(&pane, move |me, _, cx| {
-            let active_entry = me.active_entry(cx);
+            let active_entry = me.active_project_path(cx);
             me.project
-                .update(cx, |project, cx| project.set_active_entry(active_entry, cx));
+                .update(cx, |project, cx| project.set_active_path(active_entry, cx));
         })
         .detach();
         cx.subscribe(&pane, move |me, _, event, cx| {
@@ -495,7 +494,7 @@ impl Workspace {
         let entries = abs_paths
             .iter()
             .cloned()
-            .map(|path| self.entry_id_for_path(&path, cx))
+            .map(|path| self.project_path_for_path(&path, cx))
             .collect::<Vec<_>>();
 
         let fs = self.fs.clone();
@@ -562,15 +561,18 @@ impl Workspace {
         })
     }
 
-    fn entry_id_for_path(
+    fn project_path_for_path(
         &self,
         abs_path: &Path,
         cx: &mut ViewContext<Self>,
-    ) -> Task<Result<(usize, Arc<Path>)>> {
+    ) -> Task<Result<ProjectPath>> {
         let entry = self.worktree_for_abs_path(abs_path, cx);
         cx.spawn(|_, _| async move {
             let (worktree, path) = entry.await?;
-            Ok((worktree.id(), path.into()))
+            Ok(ProjectPath {
+                worktree_id: worktree.id(),
+                path: path.into(),
+            })
         })
     }
 
@@ -623,33 +625,38 @@ impl Workspace {
     #[must_use]
     pub fn open_entry(
         &mut self,
-        entry: (usize, Arc<Path>),
+        project_path: ProjectPath,
         cx: &mut ViewContext<Self>,
     ) -> Option<Task<()>> {
         let pane = self.active_pane().clone();
-        if self.activate_or_open_existing_entry(entry.clone(), &pane, cx) {
+        if self.activate_or_open_existing_entry(project_path.clone(), &pane, cx) {
             return None;
         }
 
-        let (worktree_id, path) = entry.clone();
+        // let (worktree_id, path) = project_path.clone();
 
-        let worktree = match self.project.read(cx).worktree_for_id(worktree_id) {
+        let worktree = match self
+            .project
+            .read(cx)
+            .worktree_for_id(project_path.worktree_id)
+        {
             Some(worktree) => worktree,
             None => {
-                log::error!("worktree {} does not exist", worktree_id);
+                log::error!("worktree {} does not exist", project_path.worktree_id);
                 return None;
             }
         };
 
-        if let Entry::Vacant(entry) = self.loading_items.entry(entry.clone()) {
+        if let Entry::Vacant(entry) = self.loading_items.entry(project_path.clone()) {
             let (mut tx, rx) = postage::watch::channel();
             entry.insert(rx);
 
+            let project_path = project_path.clone();
             cx.as_mut()
                 .spawn(|mut cx| async move {
                     let buffer = worktree
                         .update(&mut cx, |worktree, cx| {
-                            worktree.open_buffer(path.as_ref(), cx)
+                            worktree.open_buffer(project_path.path.as_ref(), cx)
                         })
                         .await;
                     *tx.borrow_mut() = Some(
@@ -663,7 +670,7 @@ impl Workspace {
 
         let pane = pane.downgrade();
         let settings = self.settings.clone();
-        let mut watch = self.loading_items.get(&entry).unwrap().clone();
+        let mut watch = self.loading_items.get(&project_path).unwrap().clone();
 
         Some(cx.spawn(|this, mut cx| async move {
             let load_result = loop {
@@ -674,14 +681,14 @@ impl Workspace {
             };
 
             this.update(&mut cx, |this, cx| {
-                this.loading_items.remove(&entry);
+                this.loading_items.remove(&project_path);
                 if let Some(pane) = pane.upgrade(&cx) {
                     match load_result {
                         Ok(item) => {
                             // By the time loading finishes, the entry could have been already added
                             // to the pane. If it was, we activate it, otherwise we'll store the
                             // item and add a new view for it.
-                            if !this.activate_or_open_existing_entry(entry, &pane, cx) {
+                            if !this.activate_or_open_existing_entry(project_path, &pane, cx) {
                                 let weak_item = item.downgrade();
                                 let view = weak_item
                                     .add_view(cx.window_id(), settings, cx.as_mut())
@@ -701,13 +708,13 @@ impl Workspace {
 
     fn activate_or_open_existing_entry(
         &mut self,
-        entry: (usize, Arc<Path>),
+        project_path: ProjectPath,
         pane: &ViewHandle<Pane>,
         cx: &mut ViewContext<Self>,
     ) -> bool {
         // If the pane contains a view for this file, then activate
         // that item view.
-        if pane.update(cx, |pane, cx| pane.activate_entry(entry.clone(), cx)) {
+        if pane.update(cx, |pane, cx| pane.activate_entry(project_path.clone(), cx)) {
             return true;
         }
 
@@ -718,7 +725,9 @@ impl Workspace {
         self.items.retain(|item| {
             if item.alive(cx.as_ref()) {
                 if view_for_existing_item.is_none()
-                    && item.worktree_id_and_path(cx).map_or(false, |e| e == entry)
+                    && item
+                        .project_path(cx)
+                        .map_or(false, |item_project_path| item_project_path == project_path)
                 {
                     view_for_existing_item = Some(
                         item.add_view(cx.window_id(), settings.clone(), cx.as_mut())
@@ -742,14 +751,14 @@ impl Workspace {
         self.active_pane().read(cx).active_item()
     }
 
-    fn active_entry(&self, cx: &ViewContext<Self>) -> Option<(usize, Arc<Path>)> {
-        self.active_item(cx).and_then(|item| item.entry_id(cx))
+    fn active_project_path(&self, cx: &ViewContext<Self>) -> Option<ProjectPath> {
+        self.active_item(cx).and_then(|item| item.project_path(cx))
     }
 
     pub fn save_active_item(&mut self, _: &Save, cx: &mut ViewContext<Self>) {
         if let Some(item) = self.active_item(cx) {
             let handle = cx.handle();
-            if item.entry_id(cx.as_ref()).is_none() {
+            if item.project_path(cx.as_ref()).is_none() {
                 let worktree = self.worktrees(cx).first();
                 let start_abs_path = worktree
                     .and_then(|w| w.read(cx).as_local())
@@ -885,9 +894,9 @@ impl Workspace {
         let pane = cx.add_view(|_| Pane::new(self.settings.clone()));
         let pane_id = pane.id();
         cx.observe(&pane, move |me, _, cx| {
-            let active_entry = me.active_entry(cx);
+            let active_entry = me.active_project_path(cx);
             me.project
-                .update(cx, |project, cx| project.set_active_entry(active_entry, cx));
+                .update(cx, |project, cx| project.set_active_path(active_entry, cx));
         })
         .detach();
         cx.subscribe(&pane, move |me, _, event, cx| {
@@ -1124,20 +1133,21 @@ impl View for Workspace {
 
 #[cfg(test)]
 pub trait WorkspaceHandle {
-    fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc<Path>)>;
+    fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath>;
 }
 
 #[cfg(test)]
 impl WorkspaceHandle for ViewHandle<Workspace> {
-    fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc<Path>)> {
+    fn file_project_paths(&self, cx: &AppContext) -> Vec<ProjectPath> {
         self.read(cx)
             .worktrees(cx)
             .iter()
-            .flat_map(|tree| {
-                let tree_id = tree.id();
-                tree.read(cx)
-                    .files(true, 0)
-                    .map(move |f| (tree_id, f.path.clone()))
+            .flat_map(|worktree| {
+                let worktree_id = worktree.id();
+                worktree.read(cx).files(true, 0).map(move |f| ProjectPath {
+                    worktree_id,
+                    path: f.path.clone(),
+                })
             })
             .collect::<Vec<_>>()
     }
@@ -1247,7 +1257,7 @@ mod tests {
 
         cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
             .await;
-        let entries = cx.read(|cx| workspace.file_entries(cx));
+        let entries = cx.read(|cx| workspace.file_project_paths(cx));
         let file1 = entries[0].clone();
         let file2 = entries[1].clone();
         let file3 = entries[2].clone();
@@ -1260,7 +1270,7 @@ mod tests {
         cx.read(|cx| {
             let pane = workspace.read(cx).active_pane().read(cx);
             assert_eq!(
-                pane.active_item().unwrap().entry_id(cx),
+                pane.active_item().unwrap().project_path(cx),
                 Some(file1.clone())
             );
             assert_eq!(pane.items().len(), 1);
@@ -1274,7 +1284,7 @@ mod tests {
         cx.read(|cx| {
             let pane = workspace.read(cx).active_pane().read(cx);
             assert_eq!(
-                pane.active_item().unwrap().entry_id(cx),
+                pane.active_item().unwrap().project_path(cx),
                 Some(file2.clone())
             );
             assert_eq!(pane.items().len(), 2);
@@ -1287,7 +1297,7 @@ mod tests {
         cx.read(|cx| {
             let pane = workspace.read(cx).active_pane().read(cx);
             assert_eq!(
-                pane.active_item().unwrap().entry_id(cx),
+                pane.active_item().unwrap().project_path(cx),
                 Some(file1.clone())
             );
             assert_eq!(pane.items().len(), 2);
@@ -1302,7 +1312,7 @@ mod tests {
                     .read(cx)
                     .active_item()
                     .unwrap()
-                    .entry_id(cx.as_ref()),
+                    .project_path(cx.as_ref()),
                 Some(file2.clone())
             );
         });
@@ -1319,13 +1329,13 @@ mod tests {
         cx.read(|cx| {
             let pane = workspace.read(cx).active_pane().read(cx);
             assert_eq!(
-                pane.active_item().unwrap().entry_id(cx),
+                pane.active_item().unwrap().project_path(cx),
                 Some(file3.clone())
             );
             let pane_entries = pane
                 .items()
                 .iter()
-                .map(|i| i.entry_id(cx).unwrap())
+                .map(|i| i.project_path(cx).unwrap())
                 .collect::<Vec<_>>();
             assert_eq!(pane_entries, &[file1, file2, file3]);
         });
@@ -1468,7 +1478,7 @@ mod tests {
             })
             .await
             .unwrap();
-        let tree = cx.read(|cx| {
+        let worktree = cx.read(|cx| {
             workspace
                 .read(cx)
                 .worktrees(cx)
@@ -1543,7 +1553,13 @@ mod tests {
             workspace.open_new_file(&OpenNew(app_state.clone()), cx);
             workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx);
             assert!(workspace
-                .open_entry((tree.id(), Path::new("the-new-name.rs").into()), cx)
+                .open_entry(
+                    ProjectPath {
+                        worktree_id: worktree.id(),
+                        path: Path::new("the-new-name.rs").into()
+                    },
+                    cx
+                )
                 .is_none());
         });
         let editor2 = workspace.update(&mut cx, |workspace, cx| {
@@ -1664,7 +1680,7 @@ mod tests {
             .unwrap();
         cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
             .await;
-        let entries = cx.read(|cx| workspace.file_entries(cx));
+        let entries = cx.read(|cx| workspace.file_project_paths(cx));
         let file1 = entries[0].clone();
 
         let pane_1 = cx.read(|cx| workspace.read(cx).active_pane().clone());
@@ -1675,7 +1691,7 @@ mod tests {
             .await;
         cx.read(|cx| {
             assert_eq!(
-                pane_1.read(cx).active_item().unwrap().entry_id(cx),
+                pane_1.read(cx).active_item().unwrap().project_path(cx),
                 Some(file1.clone())
             );
         });
@@ -1690,7 +1706,7 @@ mod tests {
             assert_ne!(pane_1, pane_2);
 
             let pane2_item = pane_2.read(cx).active_item().unwrap();
-            assert_eq!(pane2_item.entry_id(cx.as_ref()), Some(file1.clone()));
+            assert_eq!(pane2_item.project_path(cx.as_ref()), Some(file1.clone()));
 
             cx.dispatch_action(window_id, vec![pane_2.id()], &CloseActiveItem);
             let workspace = workspace.read(cx);

zed/src/workspace/pane.rs 🔗

@@ -1,5 +1,5 @@
 use super::{ItemViewHandle, SplitDirection};
-use crate::settings::Settings;
+use crate::{project::ProjectPath, settings::Settings};
 use gpui::{
     action,
     elements::*,
@@ -9,7 +9,7 @@ use gpui::{
     Entity, MutableAppContext, Quad, RenderContext, View, ViewContext, ViewHandle,
 };
 use postage::watch;
-use std::{cmp, path::Path, sync::Arc};
+use std::cmp;
 
 action!(Split, SplitDirection);
 action!(ActivateItem, usize);
@@ -105,12 +105,12 @@ impl Pane {
 
     pub fn activate_entry(
         &mut self,
-        entry_id: (usize, Arc<Path>),
+        project_path: ProjectPath,
         cx: &mut ViewContext<Self>,
     ) -> bool {
         if let Some(index) = self.items.iter().position(|item| {
-            item.entry_id(cx.as_ref())
-                .map_or(false, |id| id == entry_id)
+            item.project_path(cx.as_ref())
+                .map_or(false, |item_path| item_path == project_path)
         }) {
             self.activate_item(index, cx);
             true

zed/src/worktree.rs 🔗

@@ -25,10 +25,22 @@ use postage::{
 };
 use serde::Deserialize;
 use smol::channel::{self, Sender};
-use std::{any::Any, cmp::{self, Ordering}, collections::HashMap, convert::{TryFrom, TryInto}, ffi::{OsStr, OsString}, fmt, future::Future, ops::Deref, path::{Path, PathBuf}, sync::{
+use std::{
+    any::Any,
+    cmp::{self, Ordering},
+    collections::HashMap,
+    convert::{TryFrom, TryInto},
+    ffi::{OsStr, OsString},
+    fmt,
+    future::Future,
+    ops::Deref,
+    path::{Path, PathBuf},
+    sync::{
         atomic::{AtomicUsize, Ordering::SeqCst},
         Arc,
-    }, time::{Duration, SystemTime}};
+    },
+    time::{Duration, SystemTime},
+};
 use sum_tree::{self, Edit, SeekTarget, SumTree};
 use zrpc::{PeerId, TypedEnvelope};
 
@@ -1779,14 +1791,6 @@ impl File {
             mtime,
         }
     }
-
-    // pub fn exists(&self) -> bool {
-    //     !self.is_deleted()
-    // }
-
-    pub fn worktree_id_and_path(&self) -> (usize, Arc<Path>) {
-        (self.worktree.id(), self.path.clone())
-    }
 }
 
 impl buffer::File for File {