mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 10:29:35 +03:00
Fix LSP shenanigans when opening and/or editing settings files (#4212)
Fixes * LSP servers never being shut down on worktree release * worktrees (and LSP servers) being re-created for settings files on every opening Also, * removes `async` from `workspace_configuration` to simplify the code: we only return static configurations now Release Notes: - Fixed excessive LSP server creation for Zed settings files
This commit is contained in:
commit
4cccb4e3d0
@ -23,7 +23,7 @@ use async_trait::async_trait;
|
|||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{mpsc, oneshot},
|
channel::{mpsc, oneshot},
|
||||||
future::{BoxFuture, Shared},
|
future::Shared,
|
||||||
FutureExt, TryFutureExt as _,
|
FutureExt, TryFutureExt as _,
|
||||||
};
|
};
|
||||||
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
|
use gpui::{AppContext, AsyncAppContext, BackgroundExecutor, Task};
|
||||||
@ -216,11 +216,7 @@ impl CachedLspAdapter {
|
|||||||
self.adapter.code_action_kinds()
|
self.adapter.code_action_kinds()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn workspace_configuration(
|
pub fn workspace_configuration(&self, workspace_root: &Path, cx: &mut AppContext) -> Value {
|
||||||
&self,
|
|
||||||
workspace_root: &Path,
|
|
||||||
cx: &mut AppContext,
|
|
||||||
) -> BoxFuture<'static, Value> {
|
|
||||||
self.adapter.workspace_configuration(workspace_root, cx)
|
self.adapter.workspace_configuration(workspace_root, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,8 +341,8 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_configuration(&self, _: &Path, _: &mut AppContext) -> BoxFuture<'static, Value> {
|
fn workspace_configuration(&self, _: &Path, _: &mut AppContext) -> Value {
|
||||||
futures::future::ready(serde_json::json!({})).boxed()
|
serde_json::json!({})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of code actions supported by a given LspAdapter
|
/// Returns a list of code actions supported by a given LspAdapter
|
||||||
|
@ -16,7 +16,7 @@ use language::{
|
|||||||
language_settings::{Formatter, LanguageSettings},
|
language_settings::{Formatter, LanguageSettings},
|
||||||
Buffer, Language, LanguageServerName, LocalFile,
|
Buffer, Language, LanguageServerName, LocalFile,
|
||||||
};
|
};
|
||||||
use lsp::LanguageServerId;
|
use lsp::{LanguageServer, LanguageServerId};
|
||||||
use node_runtime::NodeRuntime;
|
use node_runtime::NodeRuntime;
|
||||||
use prettier::Prettier;
|
use prettier::Prettier;
|
||||||
use util::{paths::DEFAULT_PRETTIER_DIR, ResultExt, TryFutureExt};
|
use util::{paths::DEFAULT_PRETTIER_DIR, ResultExt, TryFutureExt};
|
||||||
@ -212,6 +212,10 @@ impl PrettierInstance {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn server(&self) -> Option<Arc<LanguageServer>> {
|
||||||
|
self.prettier.clone()?.await.ok()?.server().cloned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_default_prettier(
|
fn start_default_prettier(
|
||||||
|
@ -632,7 +632,7 @@ impl Project {
|
|||||||
let copilot_lsp_subscription =
|
let copilot_lsp_subscription =
|
||||||
Copilot::global(cx).map(|copilot| subscribe_for_copilot_events(&copilot, cx));
|
Copilot::global(cx).map(|copilot| subscribe_for_copilot_events(&copilot, cx));
|
||||||
Self {
|
Self {
|
||||||
worktrees: Default::default(),
|
worktrees: Vec::new(),
|
||||||
buffer_ordered_messages_tx: tx,
|
buffer_ordered_messages_tx: tx,
|
||||||
collaborators: Default::default(),
|
collaborators: Default::default(),
|
||||||
next_buffer_id: 0,
|
next_buffer_id: 0,
|
||||||
@ -664,7 +664,7 @@ impl Project {
|
|||||||
next_diagnostic_group_id: Default::default(),
|
next_diagnostic_group_id: Default::default(),
|
||||||
supplementary_language_servers: HashMap::default(),
|
supplementary_language_servers: HashMap::default(),
|
||||||
language_servers: Default::default(),
|
language_servers: Default::default(),
|
||||||
language_server_ids: Default::default(),
|
language_server_ids: HashMap::default(),
|
||||||
language_server_statuses: Default::default(),
|
language_server_statuses: Default::default(),
|
||||||
last_workspace_edits_by_language_server: Default::default(),
|
last_workspace_edits_by_language_server: Default::default(),
|
||||||
buffers_being_formatted: Default::default(),
|
buffers_being_formatted: Default::default(),
|
||||||
@ -752,7 +752,7 @@ impl Project {
|
|||||||
},
|
},
|
||||||
supplementary_language_servers: HashMap::default(),
|
supplementary_language_servers: HashMap::default(),
|
||||||
language_servers: Default::default(),
|
language_servers: Default::default(),
|
||||||
language_server_ids: Default::default(),
|
language_server_ids: HashMap::default(),
|
||||||
language_server_statuses: response
|
language_server_statuses: response
|
||||||
.payload
|
.payload
|
||||||
.language_servers
|
.language_servers
|
||||||
@ -2700,7 +2700,7 @@ impl Project {
|
|||||||
});
|
});
|
||||||
|
|
||||||
cx.spawn(move |this, mut cx| async move {
|
cx.spawn(move |this, mut cx| async move {
|
||||||
while let Some(_) = settings_changed_rx.next().await {
|
while let Some(()) = settings_changed_rx.next().await {
|
||||||
let servers: Vec<_> = this.update(&mut cx, |this, _| {
|
let servers: Vec<_> = this.update(&mut cx, |this, _| {
|
||||||
this.language_servers
|
this.language_servers
|
||||||
.values()
|
.values()
|
||||||
@ -2714,9 +2714,8 @@ impl Project {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
for (adapter, server) in servers {
|
for (adapter, server) in servers {
|
||||||
let workspace_config = cx
|
let workspace_config =
|
||||||
.update(|cx| adapter.workspace_configuration(server.root_path(), cx))?
|
cx.update(|cx| adapter.workspace_configuration(server.root_path(), cx))?;
|
||||||
.await;
|
|
||||||
server
|
server
|
||||||
.notify::<lsp::notification::DidChangeConfiguration>(
|
.notify::<lsp::notification::DidChangeConfiguration>(
|
||||||
lsp::DidChangeConfigurationParams {
|
lsp::DidChangeConfigurationParams {
|
||||||
@ -3020,9 +3019,8 @@ impl Project {
|
|||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<Arc<LanguageServer>> {
|
) -> Result<Arc<LanguageServer>> {
|
||||||
let workspace_config = cx
|
let workspace_config =
|
||||||
.update(|cx| adapter.workspace_configuration(worktree_path, cx))?
|
cx.update(|cx| adapter.workspace_configuration(worktree_path, cx))?;
|
||||||
.await;
|
|
||||||
let language_server = pending_server.task.await?;
|
let language_server = pending_server.task.await?;
|
||||||
|
|
||||||
language_server
|
language_server
|
||||||
@ -3056,9 +3054,8 @@ impl Project {
|
|||||||
let adapter = adapter.clone();
|
let adapter = adapter.clone();
|
||||||
let worktree_path = worktree_path.clone();
|
let worktree_path = worktree_path.clone();
|
||||||
async move {
|
async move {
|
||||||
let workspace_config = cx
|
let workspace_config =
|
||||||
.update(|cx| adapter.workspace_configuration(&worktree_path, cx))?
|
cx.update(|cx| adapter.workspace_configuration(&worktree_path, cx))?;
|
||||||
.await;
|
|
||||||
Ok(params
|
Ok(params
|
||||||
.items
|
.items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -6370,6 +6367,55 @@ impl Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
|
pub fn remove_worktree(&mut self, id_to_remove: WorktreeId, cx: &mut ModelContext<Self>) {
|
||||||
|
let mut servers_to_remove = HashMap::default();
|
||||||
|
let mut servers_to_preserve = HashSet::default();
|
||||||
|
for ((worktree_id, server_name), &server_id) in &self.language_server_ids {
|
||||||
|
if worktree_id == &id_to_remove {
|
||||||
|
servers_to_remove.insert(server_id, server_name.clone());
|
||||||
|
} else {
|
||||||
|
servers_to_preserve.insert(server_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
servers_to_remove.retain(|server_id, _| !servers_to_preserve.contains(server_id));
|
||||||
|
for (server_id_to_remove, server_name) in servers_to_remove {
|
||||||
|
self.language_server_ids
|
||||||
|
.remove(&(id_to_remove, server_name));
|
||||||
|
self.language_server_statuses.remove(&server_id_to_remove);
|
||||||
|
self.last_workspace_edits_by_language_server
|
||||||
|
.remove(&server_id_to_remove);
|
||||||
|
self.language_servers.remove(&server_id_to_remove);
|
||||||
|
cx.emit(Event::LanguageServerRemoved(server_id_to_remove));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut prettier_instances_to_clean = FuturesUnordered::new();
|
||||||
|
if let Some(prettier_paths) = self.prettiers_per_worktree.remove(&id_to_remove) {
|
||||||
|
for path in prettier_paths.iter().flatten() {
|
||||||
|
if let Some(prettier_instance) = self.prettier_instances.remove(path) {
|
||||||
|
prettier_instances_to_clean.push(async move {
|
||||||
|
prettier_instance
|
||||||
|
.server()
|
||||||
|
.await
|
||||||
|
.map(|server| server.server_id())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cx.spawn(|project, mut cx| async move {
|
||||||
|
while let Some(prettier_server_id) = prettier_instances_to_clean.next().await {
|
||||||
|
if let Some(prettier_server_id) = prettier_server_id {
|
||||||
|
project
|
||||||
|
.update(&mut cx, |project, cx| {
|
||||||
|
project
|
||||||
|
.supplementary_language_servers
|
||||||
|
.remove(&prettier_server_id);
|
||||||
|
cx.emit(Event::LanguageServerRemoved(prettier_server_id));
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
self.worktrees.retain(|worktree| {
|
self.worktrees.retain(|worktree| {
|
||||||
if let Some(worktree) = worktree.upgrade() {
|
if let Some(worktree) = worktree.upgrade() {
|
||||||
let id = worktree.read(cx).id();
|
let id = worktree.read(cx).id();
|
||||||
|
@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use feature_flags::FeatureFlagAppExt;
|
use feature_flags::FeatureFlagAppExt;
|
||||||
use futures::{future::BoxFuture, FutureExt, StreamExt};
|
use futures::StreamExt;
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageRegistry, LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
@ -13,7 +13,6 @@ use smol::fs;
|
|||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
future,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@ -107,7 +106,7 @@ impl LspAdapter for JsonLspAdapter {
|
|||||||
&self,
|
&self,
|
||||||
_workspace_root: &Path,
|
_workspace_root: &Path,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> BoxFuture<'static, serde_json::Value> {
|
) -> serde_json::Value {
|
||||||
let action_names = cx.all_action_names();
|
let action_names = cx.all_action_names();
|
||||||
let staff_mode = cx.is_staff();
|
let staff_mode = cx.is_staff();
|
||||||
let language_names = &self.languages.language_names();
|
let language_names = &self.languages.language_names();
|
||||||
@ -119,7 +118,7 @@ impl LspAdapter for JsonLspAdapter {
|
|||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
future::ready(serde_json::json!({
|
serde_json::json!({
|
||||||
"json": {
|
"json": {
|
||||||
"format": {
|
"format": {
|
||||||
"enable": true,
|
"enable": true,
|
||||||
@ -138,8 +137,7 @@ impl LspAdapter for JsonLspAdapter {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn language_ids(&self) -> HashMap<String, String> {
|
async fn language_ids(&self) -> HashMap<String, String> {
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::{
|
use futures::StreamExt;
|
||||||
future::{self, BoxFuture},
|
|
||||||
FutureExt, StreamExt,
|
|
||||||
};
|
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::LanguageServerBinary;
|
use lsp::LanguageServerBinary;
|
||||||
@ -107,17 +104,12 @@ impl LspAdapter for TailwindLspAdapter {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_configuration(
|
fn workspace_configuration(&self, _workspace_root: &Path, _: &mut AppContext) -> Value {
|
||||||
&self,
|
json!({
|
||||||
_workspace_root: &Path,
|
|
||||||
_: &mut AppContext,
|
|
||||||
) -> BoxFuture<'static, Value> {
|
|
||||||
future::ready(json!({
|
|
||||||
"tailwindCSS": {
|
"tailwindCSS": {
|
||||||
"emmetCompletions": true,
|
"emmetCompletions": true,
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn language_ids(&self) -> HashMap<String, String> {
|
async fn language_ids(&self) -> HashMap<String, String> {
|
||||||
|
@ -3,7 +3,6 @@ use async_compression::futures::bufread::GzipDecoder;
|
|||||||
use async_tar::Archive;
|
use async_tar::Archive;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use futures::{future::BoxFuture, FutureExt};
|
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
|
||||||
use lsp::{CodeActionKind, LanguageServerBinary};
|
use lsp::{CodeActionKind, LanguageServerBinary};
|
||||||
@ -13,7 +12,6 @@ use smol::{fs, io::BufReader, stream::StreamExt};
|
|||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
future,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@ -212,12 +210,8 @@ impl EsLintLspAdapter {
|
|||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl LspAdapter for EsLintLspAdapter {
|
impl LspAdapter for EsLintLspAdapter {
|
||||||
fn workspace_configuration(
|
fn workspace_configuration(&self, workspace_root: &Path, _: &mut AppContext) -> Value {
|
||||||
&self,
|
json!({
|
||||||
workspace_root: &Path,
|
|
||||||
_: &mut AppContext,
|
|
||||||
) -> BoxFuture<'static, Value> {
|
|
||||||
future::ready(json!({
|
|
||||||
"": {
|
"": {
|
||||||
"validate": "on",
|
"validate": "on",
|
||||||
"rulesCustomizations": [],
|
"rulesCustomizations": [],
|
||||||
@ -230,8 +224,7 @@ impl LspAdapter for EsLintLspAdapter {
|
|||||||
.unwrap_or_else(|| workspace_root.as_os_str()),
|
.unwrap_or_else(|| workspace_root.as_os_str()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn name(&self) -> LanguageServerName {
|
async fn name(&self) -> LanguageServerName {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{future::BoxFuture, FutureExt, StreamExt};
|
use futures::StreamExt;
|
||||||
use gpui::AppContext;
|
use gpui::AppContext;
|
||||||
use language::{
|
use language::{
|
||||||
language_settings::all_language_settings, LanguageServerName, LspAdapter, LspAdapterDelegate,
|
language_settings::all_language_settings, LanguageServerName, LspAdapter, LspAdapterDelegate,
|
||||||
@ -12,7 +12,6 @@ use smol::fs;
|
|||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
future,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
@ -93,24 +92,17 @@ impl LspAdapter for YamlLspAdapter {
|
|||||||
) -> Option<LanguageServerBinary> {
|
) -> Option<LanguageServerBinary> {
|
||||||
get_cached_server_binary(container_dir, &*self.node).await
|
get_cached_server_binary(container_dir, &*self.node).await
|
||||||
}
|
}
|
||||||
fn workspace_configuration(
|
fn workspace_configuration(&self, _workspace_root: &Path, cx: &mut AppContext) -> Value {
|
||||||
&self,
|
serde_json::json!({
|
||||||
_workspace_root: &Path,
|
|
||||||
cx: &mut AppContext,
|
|
||||||
) -> BoxFuture<'static, Value> {
|
|
||||||
let tab_size = all_language_settings(None, cx)
|
|
||||||
.language(Some("YAML"))
|
|
||||||
.tab_size;
|
|
||||||
|
|
||||||
future::ready(serde_json::json!({
|
|
||||||
"yaml": {
|
"yaml": {
|
||||||
"keyOrdering": false
|
"keyOrdering": false
|
||||||
},
|
},
|
||||||
"[yaml]": {
|
"[yaml]": {
|
||||||
"editor.tabSize": tab_size,
|
"editor.tabSize": all_language_settings(None, cx)
|
||||||
|
.language(Some("YAML"))
|
||||||
|
.tab_size,
|
||||||
}
|
}
|
||||||
}))
|
})
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,9 +20,10 @@ use assets::Assets;
|
|||||||
use futures::{channel::mpsc, select_biased, StreamExt};
|
use futures::{channel::mpsc, select_biased, StreamExt};
|
||||||
use project_panel::ProjectPanel;
|
use project_panel::ProjectPanel;
|
||||||
use quick_action_bar::QuickActionBar;
|
use quick_action_bar::QuickActionBar;
|
||||||
|
use rope::Rope;
|
||||||
use search::project_search::ProjectSearchBar;
|
use search::project_search::ProjectSearchBar;
|
||||||
use settings::{initial_local_settings_content, KeymapFile, Settings, SettingsStore};
|
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 terminal_view::terminal_panel::{self, TerminalPanel};
|
||||||
use util::{
|
use util::{
|
||||||
asset_str,
|
asset_str,
|
||||||
@ -256,16 +257,16 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
|
|||||||
)
|
)
|
||||||
.register_action(
|
.register_action(
|
||||||
move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
|
move |_: &mut Workspace, _: &OpenKeymap, cx: &mut ViewContext<Workspace>| {
|
||||||
create_and_open_local_file(&paths::KEYMAP, cx, Default::default)
|
open_settings_file(&paths::KEYMAP, Rope::default, cx);
|
||||||
.detach_and_log_err(cx);
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.register_action(
|
.register_action(
|
||||||
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
||||||
create_and_open_local_file(&paths::SETTINGS, cx, || {
|
open_settings_file(
|
||||||
settings::initial_user_settings_content().as_ref().into()
|
&paths::SETTINGS,
|
||||||
})
|
|| settings::initial_user_settings_content().as_ref().into(),
|
||||||
.detach_and_log_err(cx);
|
cx,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.register_action(open_local_settings_file)
|
.register_action(open_local_settings_file)
|
||||||
@ -723,6 +724,30 @@ fn open_bundled_file(
|
|||||||
.detach_and_log_err(cx);
|
.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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
Loading…
Reference in New Issue
Block a user