Create a special worktree for settings files

Kirill Bulatov and Piotr created

To avoid LSP server restarts/leaks when those are being opened

co-authored-by: Piotr <piotr@zed.dev>

Change summary

crates/gpui/src/text_system.rs    |  4 ---
crates/project/src/project.rs     |  2 
crates/workspace/src/workspace.rs |  3 -
crates/zed/src/zed.rs             | 39 +++++++++++++++++++++++++++-----
4 files changed, 34 insertions(+), 14 deletions(-)

Detailed changes

crates/gpui/src/text_system.rs 🔗

@@ -70,10 +70,6 @@ impl TextSystem {
 
     /// Get a list of all available font names from the operating system.
     pub fn all_font_names(&self) -> Vec<String> {
-        eprintln!(
-            "~~~~~~~~~~~~~ all_font_names called {}",
-            std::backtrace::Backtrace::capture()
-        );
         let mut names: BTreeSet<_> = self
             .platform_text_system
             .all_font_names()

crates/project/src/project.rs 🔗

@@ -973,7 +973,7 @@ impl Project {
         }
 
         // Start all the newly-enabled language servers.
-        for (worktree, language) in dbg!(language_servers_to_start) {
+        for (worktree, language) in language_servers_to_start {
             let worktree_path = worktree.read(cx).abs_path();
             self.start_language_servers(&worktree, worktree_path, language, cx);
         }

crates/workspace/src/workspace.rs 🔗

@@ -1355,7 +1355,7 @@ impl Workspace {
                     Some(visible) => match this
                         .update(&mut cx, |this, cx| {
                             Workspace::project_path_for_path(
-                                dbg!(this.project.clone()),
+                                this.project.clone(),
                                 abs_path,
                                 visible,
                                 cx,
@@ -1368,7 +1368,6 @@ impl Workspace {
                     },
                     None => None,
                 };
-                dbg!(&project_path);
 
                 let this = this.clone();
                 let abs_path = abs_path.clone();

crates/zed/src/zed.rs 🔗

@@ -20,9 +20,10 @@ use assets::Assets;
 use futures::{channel::mpsc, select_biased, StreamExt};
 use project_panel::ProjectPanel;
 use quick_action_bar::QuickActionBar;
+use rope::Rope;
 use search::project_search::ProjectSearchBar;
 use settings::{initial_local_settings_content, KeymapFile, Settings, SettingsStore};
-use std::{borrow::Cow, ops::Deref, sync::Arc};
+use std::{borrow::Cow, ops::Deref, path::Path, sync::Arc};
 use terminal_view::terminal_panel::{self, TerminalPanel};
 use util::{
     asset_str,
@@ -256,16 +257,16 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
             )
             .register_action(
                 move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
-                    create_and_open_local_file(&paths::KEYMAP, cx, Default::default)
-                        .detach_and_log_err(cx);
+                    open_settings_file(&paths::KEYMAP, Rope::default, cx);
                 },
             )
             .register_action(
                 move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
-                    create_and_open_local_file(&paths::SETTINGS, cx, || {
-                        settings::initial_user_settings_content().as_ref().into()
-                    })
-                    .detach_and_log_err(cx);
+                    open_settings_file(
+                        &paths::SETTINGS,
+                        || settings::initial_user_settings_content().as_ref().into(),
+                        cx,
+                    );
                 },
             )
             .register_action(open_local_settings_file)
@@ -723,6 +724,30 @@ fn open_bundled_file(
     .detach_and_log_err(cx);
 }
 
+fn open_settings_file(
+    abs_path: &'static Path,
+    default_content: impl FnOnce() -> Rope + Send + 'static,
+    cx: &mut ViewContext<Workspace>,
+) {
+    cx.spawn(|workspace, mut cx| async move {
+        let (worktree_creation_task, settings_open_task) =
+            workspace.update(&mut cx, |workspace, cx| {
+                let worktree_creation_task = workspace.project().update(cx, |project, cx| {
+                    // Set up a dedicated worktree for settings, since otherwise we're dropping and re-starting LSP servers for each file inside on every settings file close/open
+                    // TODO: Do note that all other external files (e.g. drag and drop from OS) still have their worktrees released on file close, causing LSP servers' restarts.
+                    project.find_or_create_local_worktree(paths::CONFIG_DIR.as_path(), false, cx)
+                });
+                let settings_open_task = create_and_open_local_file(&abs_path, cx, default_content);
+                (worktree_creation_task, settings_open_task)
+            })?;
+
+        let _ = worktree_creation_task.await?;
+        let _ = settings_open_task.await?;
+        anyhow::Ok(())
+    })
+    .detach_and_log_err(cx);
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;