Store a reference to the LangageRegistry on the Worktree

Nathan Sobo created

Change summary

zed/src/editor.rs        |  2 
zed/src/editor/buffer.rs | 25 ++++----------
zed/src/file_finder.rs   | 14 +++-----
zed/src/language.rs      |  6 +++
zed/src/lib.rs           |  2 
zed/src/main.rs          |  8 ++--
zed/src/rpc.rs           |  6 +-
zed/src/test.rs          |  6 +-
zed/src/workspace.rs     | 53 +++++++++++---------------------
zed/src/worktree.rs      | 68 +++++++++++++++++++++---------------------
10 files changed, 84 insertions(+), 106 deletions(-)

Detailed changes

zed/src/editor.rs 🔗

@@ -4003,7 +4003,7 @@ mod tests {
     #[gpui::test]
     async fn test_select_larger_smaller_syntax_node(mut cx: gpui::TestAppContext) {
         let app_state = cx.read(build_app_state);
-        let lang = app_state.language_registry.select_language("z.rs");
+        let lang = app_state.languages.select_language("z.rs");
         let text = r#"
             use mod1::mod2::{mod3, mod4};
 

zed/src/editor/buffer.rs 🔗

@@ -2671,7 +2671,6 @@ impl ToPoint for usize {
 mod tests {
     use super::*;
     use crate::{
-        language::LanguageRegistry,
         test::{build_app_state, temp_tree},
         util::RandomCharIter,
         worktree::{Worktree, WorktreeHandle},
@@ -3144,22 +3143,18 @@ mod tests {
 
     #[gpui::test]
     async fn test_is_dirty(mut cx: gpui::TestAppContext) {
-        let language_registry = Arc::new(LanguageRegistry::new());
-
         let dir = temp_tree(json!({
             "file1": "abc",
             "file2": "def",
             "file3": "ghi",
         }));
-        let tree = cx.add_model(|cx| Worktree::local(dir.path(), cx));
+        let tree = cx.add_model(|cx| Worktree::local(dir.path(), Default::default(), cx));
         tree.flush_fs_events(&cx).await;
         cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
             .await;
 
         let buffer1 = tree
-            .update(&mut cx, |tree, cx| {
-                tree.open_buffer("file1", language_registry.clone(), cx)
-            })
+            .update(&mut cx, |tree, cx| tree.open_buffer("file1", cx))
             .await
             .unwrap();
         let events = Rc::new(RefCell::new(Vec::new()));
@@ -3218,9 +3213,7 @@ mod tests {
         // When a file is deleted, the buffer is considered dirty.
         let events = Rc::new(RefCell::new(Vec::new()));
         let buffer2 = tree
-            .update(&mut cx, |tree, cx| {
-                tree.open_buffer("file2", language_registry.clone(), cx)
-            })
+            .update(&mut cx, |tree, cx| tree.open_buffer("file2", cx))
             .await
             .unwrap();
         buffer2.update(&mut cx, |_, cx| {
@@ -3240,9 +3233,7 @@ mod tests {
         // When a file is already dirty when deleted, we don't emit a Dirtied event.
         let events = Rc::new(RefCell::new(Vec::new()));
         let buffer3 = tree
-            .update(&mut cx, |tree, cx| {
-                tree.open_buffer("file3", language_registry.clone(), cx)
-            })
+            .update(&mut cx, |tree, cx| tree.open_buffer("file3", cx))
             .await
             .unwrap();
         buffer3.update(&mut cx, |_, cx| {
@@ -3269,14 +3260,14 @@ mod tests {
     async fn test_file_changes_on_disk(mut cx: gpui::TestAppContext) {
         let initial_contents = "aaa\nbbbbb\nc\n";
         let dir = temp_tree(json!({ "the-file": initial_contents }));
-        let tree = cx.add_model(|cx| Worktree::local(dir.path(), cx));
+        let tree = cx.add_model(|cx| Worktree::local(dir.path(), Default::default(), cx));
         cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
             .await;
 
         let abs_path = dir.path().join("the-file");
         let buffer = tree
             .update(&mut cx, |tree, cx| {
-                tree.open_buffer(Path::new("the-file"), Arc::new(LanguageRegistry::new()), cx)
+                tree.open_buffer(Path::new("the-file"), cx)
             })
             .await
             .unwrap();
@@ -3620,7 +3611,7 @@ mod tests {
     #[gpui::test]
     async fn test_reparse(mut cx: gpui::TestAppContext) {
         let app_state = cx.read(build_app_state);
-        let rust_lang = app_state.language_registry.select_language("test.rs");
+        let rust_lang = app_state.languages.select_language("test.rs");
         assert!(rust_lang.is_some());
 
         let buffer = cx.add_model(|cx| {
@@ -3761,7 +3752,7 @@ mod tests {
         use unindent::Unindent as _;
 
         let app_state = cx.read(build_app_state);
-        let rust_lang = app_state.language_registry.select_language("test.rs");
+        let rust_lang = app_state.languages.select_language("test.rs");
         assert!(rust_lang.is_some());
 
         let buffer = cx.add_model(|cx| {

zed/src/file_finder.rs 🔗

@@ -479,12 +479,8 @@ mod tests {
 
         let app_state = cx.read(build_app_state);
         let (window_id, workspace) = cx.add_window(|cx| {
-            let mut workspace = Workspace::new(
-                app_state.settings,
-                app_state.language_registry,
-                app_state.rpc,
-                cx,
-            );
+            let mut workspace =
+                Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
             workspace.add_worktree(tmp_dir.path(), cx);
             workspace
         });
@@ -553,7 +549,7 @@ mod tests {
         let (_, workspace) = cx.add_window(|cx| {
             let mut workspace = Workspace::new(
                 app_state.settings.clone(),
-                app_state.language_registry.clone(),
+                app_state.languages.clone(),
                 app_state.rpc.clone(),
                 cx,
             );
@@ -616,7 +612,7 @@ mod tests {
         let (_, workspace) = cx.add_window(|cx| {
             let mut workspace = Workspace::new(
                 app_state.settings.clone(),
-                app_state.language_registry.clone(),
+                app_state.languages.clone(),
                 app_state.rpc.clone(),
                 cx,
             );
@@ -667,7 +663,7 @@ mod tests {
         let (_, workspace) = cx.add_window(|cx| {
             Workspace::new(
                 app_state.settings.clone(),
-                app_state.language_registry.clone(),
+                app_state.languages.clone(),
                 app_state.rpc.clone(),
                 cx,
             )

zed/src/language.rs 🔗

@@ -90,6 +90,12 @@ impl LanguageRegistry {
     }
 }
 
+impl Default for LanguageRegistry {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;

zed/src/lib.rs 🔗

@@ -17,7 +17,7 @@ pub mod worktree;
 #[derive(Clone)]
 pub struct AppState {
     pub settings: postage::watch::Receiver<settings::Settings>,
-    pub language_registry: std::sync::Arc<language::LanguageRegistry>,
+    pub languages: std::sync::Arc<language::LanguageRegistry>,
     pub rpc: rpc::Client,
 }
 

zed/src/main.rs 🔗

@@ -17,13 +17,13 @@ fn main() {
     let app = gpui::App::new(assets::Assets).unwrap();
 
     let (_, settings) = settings::channel(&app.font_cache()).unwrap();
-    let language_registry = Arc::new(language::LanguageRegistry::new());
-    language_registry.set_theme(&settings.borrow().theme);
+    let languages = Arc::new(language::LanguageRegistry::new());
+    languages.set_theme(&settings.borrow().theme);
 
     let app_state = AppState {
-        language_registry: language_registry.clone(),
+        languages: languages.clone(),
         settings,
-        rpc: rpc::Client::new(language_registry),
+        rpc: rpc::Client::new(languages),
     };
 
     app.run(move |cx| {

zed/src/rpc.rs 🔗

@@ -31,7 +31,7 @@ pub struct ClientState {
     connection_id: Option<ConnectionId>,
     pub remote_worktrees: HashMap<u64, WeakModelHandle<Worktree>>,
     pub shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
-    pub language_registry: Arc<LanguageRegistry>,
+    pub languages: Arc<LanguageRegistry>,
 }
 
 impl ClientState {
@@ -54,14 +54,14 @@ impl ClientState {
 }
 
 impl Client {
-    pub fn new(language_registry: Arc<LanguageRegistry>) -> Self {
+    pub fn new(languages: Arc<LanguageRegistry>) -> Self {
         Self {
             peer: Peer::new(),
             state: Arc::new(Mutex::new(ClientState {
                 connection_id: None,
                 remote_worktrees: Default::default(),
                 shared_buffers: Default::default(),
-                language_registry,
+                languages,
             })),
         }
     }

zed/src/test.rs 🔗

@@ -142,10 +142,10 @@ fn write_tree(path: &Path, tree: serde_json::Value) {
 
 pub fn build_app_state(cx: &AppContext) -> AppState {
     let settings = settings::channel(&cx.font_cache()).unwrap().1;
-    let language_registry = Arc::new(LanguageRegistry::new());
+    let languages = Arc::new(LanguageRegistry::new());
     AppState {
         settings,
-        language_registry: language_registry.clone(),
-        rpc: rpc::Client::new(language_registry),
+        languages: languages.clone(),
+        rpc: rpc::Client::new(languages),
     }
 }

zed/src/workspace.rs 🔗

@@ -91,7 +91,7 @@ fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) {
     cx.add_window(|cx| {
         let mut view = Workspace::new(
             params.app_state.settings.clone(),
-            params.app_state.language_registry.clone(),
+            params.app_state.languages.clone(),
             params.app_state.rpc.clone(),
             cx,
         );
@@ -105,7 +105,7 @@ fn open_new(app_state: &AppState, cx: &mut MutableAppContext) {
     cx.add_window(|cx| {
         let mut view = Workspace::new(
             app_state.settings.clone(),
-            app_state.language_registry.clone(),
+            app_state.languages.clone(),
             app_state.rpc.clone(),
             cx,
         );
@@ -312,7 +312,7 @@ pub struct State {
 
 pub struct Workspace {
     pub settings: watch::Receiver<Settings>,
-    language_registry: Arc<LanguageRegistry>,
+    languages: Arc<LanguageRegistry>,
     rpc: rpc::Client,
     modal: Option<AnyViewHandle>,
     center: PaneGroup,
@@ -329,7 +329,7 @@ pub struct Workspace {
 impl Workspace {
     pub fn new(
         settings: watch::Receiver<Settings>,
-        language_registry: Arc<LanguageRegistry>,
+        languages: Arc<LanguageRegistry>,
         rpc: rpc::Client,
         cx: &mut ViewContext<Self>,
     ) -> Self {
@@ -346,7 +346,7 @@ impl Workspace {
             panes: vec![pane.clone()],
             active_pane: pane.clone(),
             settings,
-            language_registry,
+            languages: languages,
             rpc,
             worktrees: Default::default(),
             items: Default::default(),
@@ -462,7 +462,7 @@ impl Workspace {
         path: &Path,
         cx: &mut ViewContext<Self>,
     ) -> ModelHandle<Worktree> {
-        let worktree = cx.add_model(|cx| Worktree::local(path, cx));
+        let worktree = cx.add_model(|cx| Worktree::local(path, self.languages.clone(), cx));
         cx.observe_model(&worktree, |_, _, cx| cx.notify());
         self.worktrees.insert(worktree.clone());
         cx.notify();
@@ -558,13 +558,12 @@ impl Workspace {
         if let Entry::Vacant(entry) = self.loading_items.entry(entry.clone()) {
             let (mut tx, rx) = postage::watch::channel();
             entry.insert(rx);
-            let language_registry = self.language_registry.clone();
 
             cx.as_mut()
                 .spawn(|mut cx| async move {
                     let buffer = worktree
                         .update(&mut cx, |worktree, cx| {
-                            worktree.open_buffer(path.as_ref(), language_registry, cx)
+                            worktree.open_buffer(path.as_ref(), cx)
                         })
                         .await;
                     *tx.borrow_mut() = Some(
@@ -714,6 +713,7 @@ impl Workspace {
 
     fn join_worktree(&mut self, _: &(), cx: &mut ViewContext<Self>) {
         let rpc = self.rpc.clone();
+        let languages = self.languages.clone();
 
         let task = cx.spawn(|this, mut cx| async move {
             rpc.log_in_and_connect(&cx).await?;
@@ -727,7 +727,8 @@ impl Workspace {
             log::info!("read worktree url from clipboard: {}", worktree_url.text());
 
             let worktree =
-                Worktree::remote(rpc.clone(), worktree_id, access_token, &mut cx).await?;
+                Worktree::remote(rpc.clone(), worktree_id, access_token, languages, &mut cx)
+                    .await?;
             this.update(&mut cx, |workspace, cx| {
                 cx.observe_model(&worktree, |_, _, cx| cx.notify());
                 workspace.worktrees.insert(worktree);
@@ -961,12 +962,8 @@ mod tests {
         let app_state = cx.read(build_app_state);
 
         let (_, workspace) = cx.add_window(|cx| {
-            let mut workspace = Workspace::new(
-                app_state.settings,
-                app_state.language_registry,
-                app_state.rpc,
-                cx,
-            );
+            let mut workspace =
+                Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
             workspace.add_worktree(dir.path(), cx);
             workspace
         });
@@ -1069,12 +1066,8 @@ mod tests {
 
         let app_state = cx.read(build_app_state);
         let (_, workspace) = cx.add_window(|cx| {
-            let mut workspace = Workspace::new(
-                app_state.settings,
-                app_state.language_registry,
-                app_state.rpc,
-                cx,
-            );
+            let mut workspace =
+                Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
             workspace.add_worktree(dir1.path(), cx);
             workspace
         });
@@ -1142,12 +1135,8 @@ mod tests {
 
         let app_state = cx.read(build_app_state);
         let (window_id, workspace) = cx.add_window(|cx| {
-            let mut workspace = Workspace::new(
-                app_state.settings,
-                app_state.language_registry,
-                app_state.rpc,
-                cx,
-            );
+            let mut workspace =
+                Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
             workspace.add_worktree(dir.path(), cx);
             workspace
         });
@@ -1192,7 +1181,7 @@ mod tests {
         let (_, workspace) = cx.add_window(|cx| {
             let mut workspace = Workspace::new(
                 app_state.settings.clone(),
-                app_state.language_registry.clone(),
+                app_state.languages.clone(),
                 app_state.rpc.clone(),
                 cx,
             );
@@ -1315,12 +1304,8 @@ mod tests {
 
         let app_state = cx.read(build_app_state);
         let (window_id, workspace) = cx.add_window(|cx| {
-            let mut workspace = Workspace::new(
-                app_state.settings,
-                app_state.language_registry,
-                app_state.rpc,
-                cx,
-            );
+            let mut workspace =
+                Workspace::new(app_state.settings, app_state.languages, app_state.rpc, cx);
             workspace.add_worktree(dir.path(), cx);
             workspace
         });

zed/src/worktree.rs 🔗

@@ -74,14 +74,19 @@ impl Entity for Worktree {
 }
 
 impl Worktree {
-    pub fn local(path: impl Into<Arc<Path>>, cx: &mut ModelContext<Worktree>) -> Self {
-        Worktree::Local(LocalWorktree::new(path, cx))
+    pub fn local(
+        path: impl Into<Arc<Path>>,
+        languages: Arc<LanguageRegistry>,
+        cx: &mut ModelContext<Worktree>,
+    ) -> Self {
+        Worktree::Local(LocalWorktree::new(path, languages, cx))
     }
 
     pub async fn remote(
         rpc: rpc::Client,
         id: u64,
         access_token: String,
+        languages: Arc<LanguageRegistry>,
         cx: &mut AsyncAppContext,
     ) -> Result<ModelHandle<Self>> {
         let open_worktree_response = rpc
@@ -103,6 +108,7 @@ impl Worktree {
                     worktree_message,
                     rpc.clone(),
                     replica_id as ReplicaId,
+                    languages,
                     cx,
                 ))
             })
@@ -149,14 +155,11 @@ impl Worktree {
     pub fn open_buffer(
         &mut self,
         path: impl AsRef<Path>,
-        language_registry: Arc<LanguageRegistry>,
         cx: &mut ModelContext<Self>,
     ) -> Task<Result<ModelHandle<Buffer>>> {
         match self {
-            Worktree::Local(worktree) => worktree.open_buffer(path.as_ref(), language_registry, cx),
-            Worktree::Remote(worktree) => {
-                worktree.open_buffer(path.as_ref(), language_registry, cx)
-            }
+            Worktree::Local(worktree) => worktree.open_buffer(path.as_ref(), cx),
+            Worktree::Remote(worktree) => worktree.open_buffer(path.as_ref(), cx),
         }
     }
 
@@ -241,10 +244,15 @@ pub struct LocalWorktree {
     poll_scheduled: bool,
     rpc: Option<(rpc::Client, u64)>,
     open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
+    languages: Arc<LanguageRegistry>,
 }
 
 impl LocalWorktree {
-    fn new(path: impl Into<Arc<Path>>, cx: &mut ModelContext<Worktree>) -> Self {
+    fn new(
+        path: impl Into<Arc<Path>>,
+        languages: Arc<LanguageRegistry>,
+        cx: &mut ModelContext<Worktree>,
+    ) -> Self {
         let abs_path = path.into();
         let (scan_state_tx, scan_state_rx) = smol::channel::unbounded();
         let id = cx.model_id();
@@ -268,11 +276,12 @@ impl LocalWorktree {
         let tree = Self {
             snapshot,
             background_snapshot: background_snapshot.clone(),
-            open_buffers: Default::default(),
             scan_state: watch::channel_with(ScanState::Scanning),
             _event_stream_handle: event_stream_handle,
             poll_scheduled: false,
+            open_buffers: Default::default(),
             rpc: None,
+            languages,
         };
 
         std::thread::spawn(move || {
@@ -313,7 +322,6 @@ impl LocalWorktree {
     pub fn open_buffer(
         &mut self,
         path: &Path,
-        language_registry: Arc<LanguageRegistry>,
         cx: &mut ModelContext<Worktree>,
     ) -> Task<Result<ModelHandle<Buffer>>> {
         let handle = cx.handle();
@@ -333,6 +341,7 @@ impl LocalWorktree {
             }
         });
 
+        let languages = self.languages.clone();
         let path = Arc::from(path);
         cx.spawn(|this, mut cx| async move {
             if let Some(existing_buffer) = existing_buffer {
@@ -341,7 +350,7 @@ impl LocalWorktree {
                 let (file, contents) = this
                     .update(&mut cx, |this, cx| this.as_local().unwrap().load(&path, cx))
                     .await?;
-                let language = language_registry.select_language(&path).cloned();
+                let language = languages.select_language(&path).cloned();
                 let buffer = cx.add_model(|cx| {
                     Buffer::from_history(0, History::new(contents.into()), Some(file), language, cx)
                 });
@@ -638,6 +647,7 @@ pub struct RemoteWorktree {
     rpc: rpc::Client,
     replica_id: ReplicaId,
     open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
+    languages: Arc<LanguageRegistry>,
 }
 
 impl RemoteWorktree {
@@ -646,6 +656,7 @@ impl RemoteWorktree {
         worktree: proto::Worktree,
         rpc: rpc::Client,
         replica_id: ReplicaId,
+        languages: Arc<LanguageRegistry>,
         cx: &mut ModelContext<Worktree>,
     ) -> Self {
         let root_char_bag: CharBag = worktree
@@ -700,13 +711,13 @@ impl RemoteWorktree {
             rpc,
             replica_id,
             open_buffers: Default::default(),
+            languages,
         }
     }
 
     pub fn open_buffer(
         &mut self,
         path: &Path,
-        language_registry: Arc<LanguageRegistry>,
         cx: &mut ModelContext<Worktree>,
     ) -> Task<Result<ModelHandle<Buffer>>> {
         let handle = cx.handle();
@@ -725,6 +736,7 @@ impl RemoteWorktree {
         });
 
         let rpc = self.rpc.clone();
+        let languages = self.languages.clone();
         let replica_id = self.replica_id;
         let remote_worktree_id = self.remote_id;
         let path = path.to_string_lossy().to_string();
@@ -736,7 +748,7 @@ impl RemoteWorktree {
                     .read_with(&cx, |tree, _| tree.entry_for_path(&path).cloned())
                     .ok_or_else(|| anyhow!("file does not exist"))?;
                 let file = File::new(entry.id, handle, entry.path, entry.mtime);
-                let language = language_registry.select_language(&path).cloned();
+                let language = languages.select_language(&path).cloned();
                 let response = rpc
                     .request(proto::OpenBuffer {
                         worktree_id: remote_worktree_id as u64,
@@ -1880,11 +1892,7 @@ mod remote {
 
         let buffer = worktree
             .update(cx, |worktree, cx| {
-                worktree.open_buffer(
-                    Path::new(&message.path),
-                    state.language_registry.clone(),
-                    cx,
-                )
+                worktree.open_buffer(Path::new(&message.path), cx)
             })
             .await?;
         state
@@ -2026,7 +2034,7 @@ mod tests {
         )
         .unwrap();
 
-        let tree = cx.add_model(|cx| Worktree::local(root_link_path, cx));
+        let tree = cx.add_model(|cx| Worktree::local(root_link_path, Default::default(), cx));
 
         cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
             .await;
@@ -2068,11 +2076,9 @@ mod tests {
         let dir = temp_tree(json!({
             "file1": "the old contents",
         }));
-        let tree = cx.add_model(|cx| Worktree::local(dir.path(), cx));
+        let tree = cx.add_model(|cx| Worktree::local(dir.path(), app_state.languages, cx));
         let buffer = tree
-            .update(&mut cx, |tree, cx| {
-                tree.open_buffer("file1", app_state.language_registry, cx)
-            })
+            .update(&mut cx, |tree, cx| tree.open_buffer("file1", cx))
             .await
             .unwrap();
         let save = buffer.update(&mut cx, |buffer, cx| {
@@ -2093,15 +2099,13 @@ mod tests {
         }));
         let file_path = dir.path().join("file1");
 
-        let tree = cx.add_model(|cx| Worktree::local(file_path.clone(), cx));
+        let tree = cx.add_model(|cx| Worktree::local(file_path.clone(), app_state.languages, cx));
         cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
             .await;
         cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1));
 
         let buffer = tree
-            .update(&mut cx, |tree, cx| {
-                tree.open_buffer("", app_state.language_registry, cx)
-            })
+            .update(&mut cx, |tree, cx| tree.open_buffer("", cx))
             .await
             .unwrap();
         let save = buffer.update(&mut cx, |buffer, cx| {
@@ -2130,14 +2134,10 @@ mod tests {
             }
         }));
 
-        let language_registry = Arc::new(LanguageRegistry::new());
-
-        let tree = cx.add_model(|cx| Worktree::local(dir.path(), cx));
+        let tree = cx.add_model(|cx| Worktree::local(dir.path(), Default::default(), cx));
 
         let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| {
-            let buffer = tree.update(cx, |tree, cx| {
-                tree.open_buffer(path, language_registry.clone(), cx)
-            });
+            let buffer = tree.update(cx, |tree, cx| tree.open_buffer(path, cx));
             async move { buffer.await.unwrap() }
         };
         let id_for_path = |path: &'static str, cx: &gpui::TestAppContext| {
@@ -2233,7 +2233,7 @@ mod tests {
             }
         }));
 
-        let tree = cx.add_model(|cx| Worktree::local(dir.path(), cx));
+        let tree = cx.add_model(|cx| Worktree::local(dir.path(), Default::default(), cx));
         cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
             .await;
         tree.flush_fs_events(&cx).await;