Remove worktree-specific methods from language::File trait

Max Brunsfeld created

Use downcasting instead for accessing worktree-specific state of the Files.

This will allow us to introduce a WorktreeId type and use that everywhere
for identifying worktrees. It also just removes some unnecessary coupling
between the language crate and the worktree.

Change summary

crates/editor/src/items.rs     | 10 ++++----
crates/language/src/buffer.rs  |  6 -----
crates/project/src/worktree.rs | 38 +++++++++++++++++------------------
3 files changed, 23 insertions(+), 31 deletions(-)

Detailed changes

crates/editor/src/items.rs 🔗

@@ -7,7 +7,7 @@ use gpui::{
 };
 use language::{Diagnostic, File as _};
 use postage::watch;
-use project::{ProjectPath, Worktree};
+use project::{File, ProjectPath, Worktree};
 use std::fmt::Write;
 use std::path::Path;
 use text::{Point, Selection};
@@ -66,8 +66,8 @@ impl ItemHandle for BufferItemHandle {
     }
 
     fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
-        self.0.read(cx).file(cx).map(|f| ProjectPath {
-            worktree_id: f.worktree_id(),
+        File::from_dyn(self.0.read(cx).file(cx)).map(|f| ProjectPath {
+            worktree_id: f.worktree_id(cx),
             path: f.path().clone(),
         })
     }
@@ -111,8 +111,8 @@ impl ItemView for Editor {
     }
 
     fn project_path(&self, cx: &AppContext) -> Option<ProjectPath> {
-        self.buffer().read(cx).file(cx).map(|file| ProjectPath {
-            worktree_id: file.worktree_id(),
+        File::from_dyn(self.buffer().read(cx).file(cx)).map(|file| ProjectPath {
+            worktree_id: file.worktree_id(cx),
             path: file.path().clone(),
         })
     }

crates/language/src/buffer.rs 🔗

@@ -149,10 +149,6 @@ pub enum Event {
 }
 
 pub trait File {
-    fn worktree_id(&self) -> usize;
-
-    fn entry_id(&self) -> Option<usize>;
-
     fn mtime(&self) -> SystemTime;
 
     /// Returns the path of this file relative to the worktree's root directory.
@@ -185,8 +181,6 @@ pub trait File {
 
     fn buffer_removed(&self, buffer_id: u64, cx: &mut MutableAppContext);
 
-    fn boxed_clone(&self) -> Box<dyn File>;
-
     fn as_any(&self) -> &dyn Any;
 }
 

crates/project/src/worktree.rs 🔗

@@ -619,9 +619,9 @@ impl Worktree {
         for (buffer_id, buffer) in open_buffers {
             if let Some(buffer) = buffer.upgrade(cx) {
                 buffer.update(cx, |buffer, cx| {
-                    if let Some(old_file) = buffer.file() {
+                    if let Some(old_file) = File::from_dyn(buffer.file()) {
                         let new_file = if let Some(entry) = old_file
-                            .entry_id()
+                            .entry_id
                             .and_then(|entry_id| self.entry_for_id(entry_id))
                         {
                             File {
@@ -1108,12 +1108,12 @@ impl LocalWorktree {
         path: &Path,
         cx: &mut ModelContext<Worktree>,
     ) -> Option<ModelHandle<Buffer>> {
-        let worktree_id = self.id();
+        let handle = cx.handle();
         let mut result = None;
         self.open_buffers.retain(|_buffer_id, buffer| {
-            if let Some(buffer) = buffer.upgrade(cx.as_ref()) {
-                if let Some(file) = buffer.read(cx.as_ref()).file() {
-                    if file.worktree_id() == worktree_id && file.path().as_ref() == path {
+            if let Some(buffer) = buffer.upgrade(cx) {
+                if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
+                    if file.worktree == handle && file.path().as_ref() == path {
                         result = Some(buffer);
                     }
                 }
@@ -1446,8 +1446,8 @@ impl RemoteWorktree {
         let mut existing_buffer = None;
         self.open_buffers.retain(|_buffer_id, buffer| {
             if let Some(buffer) = buffer.upgrade(cx.as_ref()) {
-                if let Some(file) = buffer.read(cx.as_ref()).file() {
-                    if file.worktree_id() == handle.id() && file.path().as_ref() == path {
+                if let Some(file) = File::from_dyn(buffer.read(cx).file()) {
+                    if file.worktree == handle && file.path().as_ref() == path {
                         existing_buffer = Some(buffer);
                     }
                 }
@@ -1958,14 +1958,6 @@ pub struct File {
 }
 
 impl language::File for File {
-    fn worktree_id(&self) -> usize {
-        self.worktree.id()
-    }
-
-    fn entry_id(&self) -> Option<usize> {
-        self.entry_id
-    }
-
     fn mtime(&self) -> SystemTime {
         self.mtime
     }
@@ -2094,15 +2086,21 @@ impl language::File for File {
         });
     }
 
-    fn boxed_clone(&self) -> Box<dyn language::File> {
-        Box::new(self.clone())
-    }
-
     fn as_any(&self) -> &dyn Any {
         self
     }
 }
 
+impl File {
+    pub fn from_dyn(file: Option<&dyn language::File>) -> Option<&Self> {
+        file.and_then(|f| f.as_any().downcast_ref())
+    }
+
+    pub fn worktree_id(&self, cx: &AppContext) -> usize {
+        self.worktree.read(cx).id()
+    }
+}
+
 #[derive(Clone, Debug)]
 pub struct Entry {
     pub id: usize,