Revert "Refactor lsp store (#17435)" (#17484)

This reverts commit 8a1e8e37bb (PR #17435)
because it creates a panic when joining a collab project.

Stack trace of the panic:

```
Thread "main" panicked with "ProjectLspAdapterDelegate cannot be constructedd on an ssh-remote yet" at crates/project/src/lsp_store.rs:6332:13
   0: backtrace::backtrace::libunwind::trace
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/backtrace-0.3.73/src/backtrace/libunwind.rs:116:5
      backtrace::backtrace::trace_unsynchronized::<<backtrace::capture::Backtrace>::create::{closure#0}>
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/backtrace-0.3.73/src/backtrace/mod.rs:66:5
   1: backtrace::backtrace::trace::<<backtrace::capture::Backtrace>::create::{closure#0}>
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/backtrace-0.3.73/src/backtrace/mod.rs:53:14
   2: <backtrace::capture::Backtrace>::create
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/backtrace-0.3.73/src/capture.rs:197:9
   3: <backtrace::capture::Backtrace>::new
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/backtrace-0.3.73/src/capture.rs:162:22
   4: zed::reliability::init_panic_hook::{closure#0}
             at /Users/thorstenball/work/zed/crates/zed/src/reliability.rs:58:29
   5: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/alloc/src/boxed.rs:2084:9
      std::panicking::rust_panic_with_hook
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:808:13
   6: std::panicking::begin_panic_handler::{{closure}}
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:667:13
   7: std::sys::backtrace::__rust_end_short_backtrace
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/backtrace.rs:168:18
   8: rust_begin_unwind
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:665:5
   9: core::panicking::panic_fmt
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/panicking.rs:74:14
  10: <project::lsp_store::ProjectLspAdapterDelegate>::new
             at /Users/thorstenball/work/zed/crates/project/src/lsp_store.rs:6332:13
  11: assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}::{closure#1}
             at /Users/thorstenball/work/zed/crates/assistant/src/assistant_panel.rs:5159:16
  12: <gpui::app::AppContext as gpui::Context>::update_model::<project::lsp_store::LspStore, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}::{closure#1}>::{closure#0}
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:1365:26
  13: <gpui::app::AppContext>::update::<core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, <gpui::app::AppContext as gpui::Context>::update_model<project::lsp_store::LspStore, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}::{closure#1}>::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:362:22
  14: <gpui::app::AppContext as gpui::Context>::update_model::<project::lsp_store::LspStore, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}::{closure#1}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:1363:9
  15: <gpui::app::model_context::ModelContext<project::Project> as gpui::Context>::update_model::<project::lsp_store::LspStore, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}::{closure#1}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app/model_context.rs:250:9
  16: <gpui::app::entity_map::Model<project::lsp_store::LspStore>>::update::<gpui::app::model_context::ModelContext<project::Project>, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}::{closure#1}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app/entity_map.rs:422:9
  17: assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}
             at /Users/thorstenball/work/zed/crates/assistant/src/assistant_panel.rs:5158:9
  18: <gpui::app::AppContext as gpui::Context>::update_model::<project::Project, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}>::{closure#0}
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:1365:26
  19: <gpui::app::AppContext>::update::<core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, <gpui::app::AppContext as gpui::Context>::update_model<project::Project, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}>::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:362:22
  20: <gpui::app::AppContext as gpui::Context>::update_model::<project::Project, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:1363:9
  21: <gpui::app::entity_map::Model<project::Project>>::update::<gpui::app::AppContext, core::result::Result<alloc::sync::Arc<dyn language::LspAdapterDelegate>, anyhow::Error>, assistant::assistant_panel::make_lsp_adapter_delegate::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app/entity_map.rs:422:9
  22: assistant::assistant_panel::make_lsp_adapter_delegate
             at /Users/thorstenball/work/zed/crates/assistant/src/assistant_panel.rs:5152:5
  23: <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}
             at /Users/thorstenball/work/zed/crates/assistant/src/assistant_panel.rs:960:48
  24: <gpui:🪟:WindowContext as gpui::VisualContext>::update_view::<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/window.rs:3940:22
  25: <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view::<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>::{closure#0}
             at /Users/thorstenball/work/zed/crates/gpui/src/app/async_context.rs:387:35
  26: <gpui::app::AppContext as gpui::Context>::update_window::<core::result::Result<(), anyhow::Error>, <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>::{closure#0}>::{closure#0}
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:1396:26
  27: <gpui::app::AppContext>::update::<core::result::Result<core::result::Result<(), anyhow::Error>, anyhow::Error>, <gpui::app::AppContext as gpui::Context>::update_window<core::result::Result<(), anyhow::Error>, <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>::{closure#0}>::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:362:22
  28: <gpui::app::AppContext as gpui::Context>::update_window::<core::result::Result<(), anyhow::Error>, <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:1387:9
  29: <gpui::app::async_context::AsyncAppContext as gpui::Context>::update_window::<core::result::Result<(), anyhow::Error>, <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app/async_context.rs:91:9
  30: <gpui::app::async_context::AsyncWindowContext as gpui::Context>::update_window::<core::result::Result<(), anyhow::Error>, <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app/async_context.rs:354:9
  31: <gpui:🪟:AnyWindowHandle>::update::<gpui::app::async_context::AsyncWindowContext, core::result::Result<(), anyhow::Error>, <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/window.rs:4800:9
  32: <gpui::app::async_context::AsyncWindowContext as gpui::VisualContext>::update_view::<assistant::assistant_panel::AssistantPanel, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app/async_context.rs:386:9
  33: <gpui::view::View<assistant::assistant_panel::AssistantPanel>>::update::<gpui::app::async_context::AsyncWindowContext, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/view.rs:76:9
  34: <gpui::view::WeakView<assistant::assistant_panel::AssistantPanel>>::update::<gpui::app::async_context::AsyncWindowContext, core::result::Result<(), anyhow::Error>, <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}::{closure#0}>
             at /Users/thorstenball/work/zed/crates/gpui/src/view.rs:192:12
  35: <assistant::assistant_panel::AssistantPanel>::new_context::{closure#1}::{closure#0}
             at /Users/thorstenball/work/zed/crates/assistant/src/assistant_panel.rs:957:17
  36: <core::pin::Pin<alloc::boxed::Box<dyn core::future::future::Future<Output = core::result::Result<(), anyhow::Error>>>> as core::future::future::Future>::poll
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/future/future.rs:123:9
  37: <<async_task::runnable::Builder<_>>::spawn_local::Checked<core::pin::Pin<alloc::boxed::Box<dyn core::future::future::Future<Output = core::result::Result<(), anyhow::Error>>>>> as core::future::future::Future>::poll
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-task-4.7.1/src/runnable.rs:455:26
  38: <async_task::raw::RawTask<<async_task::runnable::Builder<_>>::spawn_local::Checked<core::pin::Pin<alloc::boxed::Box<dyn core::future::future::Future<Output = core::result::Result<(), anyhow::Error>>>>>, core::result::Result<(), anyhow::Error>, <gpui::executor::ForegroundExecutor>::spawn::inner<core::result::Result<(), anyhow::Error>>::{closure#0}, ()>>::run
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-task-4.7.1/src/raw.rs:557:17
  39: <async_task::runnable::Runnable>::run
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/async-task-4.7.1/src/runnable.rs:781:18
  40: gpui::platform::mac::dispatcher::trampoline
             at /Users/thorstenball/work/zed/crates/gpui/src/platform/mac/dispatcher.rs:106:5
  41: <unknown>
  42: <unknown>
  43: <unknown>
  44: <unknown>
  45: <unknown>
  46: <unknown>
  47: <unknown>
  48: <unknown>
  49: <unknown>
  50: <unknown>
  51: <unknown>
  52: <unknown>
  53: <() as objc::message::MessageArguments>::invoke::<()>
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/objc-0.2.7/src/message/mod.rs:128:17
  54: objc::message::platform::send_unverified::<objc::runtime::Object, (), ()>
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/objc-0.2.7/src/message/apple/mod.rs:27:9
  55: objc::message::send_message::<objc::runtime::Object, (), ()>
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/objc-0.2.7/src/message/mod.rs:178:5
      <*mut objc::runtime::Object as cocoa::appkit::NSApplication>::run
             at /Users/thorstenball/.cargo/registry/src/index.crates.io-6f17d22bba15001f/cocoa-0.26.0/src/appkit.rs:628:9
  56: <gpui::platform::mac::platform::MacPlatform as gpui::platform::Platform>::run
             at /Users/thorstenball/work/zed/crates/gpui/src/platform/mac/platform.rs:427:13
  57: <gpui::app::App>::run::<zed::main::{closure#3}>
             at /Users/thorstenball/work/zed/crates/gpui/src/app.rs:159:9
  58: zed::main
             at /Users/thorstenball/work/zed/crates/zed/src/main.rs:439:5
  59: <fn() as core::ops::function::FnOnce<()>>::call_once
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/ops/function.rs:250:5
  60: std::sys::backtrace::__rust_begin_short_backtrace::<fn(), ()>
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/sys/backtrace.rs:152:18
  61: std::rt::lang_start::<()>::{closure#0}
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/rt.rs:162:18
  62: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/core/src/ops/function.rs:284:13
      std::panicking
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:557:40
      std::panicking::try
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:521:19
      std::panic::catch_unwind
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panic.rs:350:14
      std::rt::lang_start_internal::{{closure}}
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/rt.rs:141:48
      std::panicking::try::do_call
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:557:40
      std::panicking::try
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panicking.rs:521:19
      std::panic::catch_unwind
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/panic.rs:350:14
      std::rt::lang_start_internal
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/rt.rs:141:20
  63: std::rt::lang_start::<()>
             at /rustc/eeb90cda1969383f56a2637cbd3037bdf598841c/library/std/src/rt.rs:161:17
  64: _main
```

Closes #ISSUE

Release Notes:

- Added/Fixed/Improved ...

Optionally, include screenshots / media showcasing your addition that
can be included in the release notes.

### Or...

Closes #ISSUE

Release Notes:

- N/A

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-09-06 10:25:36 +02:00 committed by GitHub
parent a6b1c054a8
commit fbac7dcd10
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 455 additions and 726 deletions

View File

@ -688,7 +688,7 @@ impl LspLogView {
self.project
.read(cx)
.supplementary_language_servers(cx)
.filter_map(|(server_id, name)| {
.filter_map(|(&server_id, name)| {
let state = log_store.language_servers.get(&server_id)?;
Some(LogMenuItem {
server_id,

View File

@ -85,82 +85,27 @@ const SERVER_REINSTALL_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
pub struct LocalLspStore {
http_client: Option<Arc<dyn HttpClient>>,
environment: Model<ProjectEnvironment>,
fs: Arc<dyn Fs>,
yarn: Model<YarnPathStore>,
language_servers: HashMap<LanguageServerId, LanguageServerState>,
last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
language_server_watched_paths: HashMap<LanguageServerId, HashMap<WorktreeId, GlobSet>>,
language_server_watcher_registrations:
HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
supplementary_language_servers:
HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
_subscription: gpui::Subscription,
}
impl LocalLspStore {
fn shutdown_language_servers(
&mut self,
_cx: &mut ModelContext<LspStore>,
) -> impl Future<Output = ()> {
let shutdown_futures = self
.language_servers
.drain()
.map(|(_, server_state)| async {
use LanguageServerState::*;
match server_state {
Running { server, .. } => server.shutdown()?.await,
Starting(task) => task.await?.shutdown()?.await,
}
})
.collect::<Vec<_>>();
async move {
futures::future::join_all(shutdown_futures).await;
}
}
}
pub struct RemoteLspStore {
upstream_client: AnyProtoClient,
}
impl RemoteLspStore {}
pub struct SshLspStore {
upstream_client: AnyProtoClient,
}
#[allow(clippy::large_enum_variant)]
pub enum LspStoreMode {
Local(LocalLspStore), // ssh host and collab host
Remote(RemoteLspStore), // collab guest
Ssh(SshLspStore), // ssh client
}
impl LspStoreMode {
fn is_local(&self) -> bool {
matches!(self, LspStoreMode::Local(_))
}
fn is_ssh(&self) -> bool {
matches!(self, LspStoreMode::Ssh(_))
}
}
pub struct LspStore {
mode: LspStoreMode,
downstream_client: Option<AnyProtoClient>,
upstream_client: Option<AnyProtoClient>,
project_id: u64,
http_client: Option<Arc<dyn HttpClient>>,
fs: Arc<dyn Fs>,
nonce: u128,
buffer_store: Model<BufferStore>,
worktree_store: Model<WorktreeStore>,
buffer_snapshots: HashMap<BufferId, HashMap<LanguageServerId, Vec<LspBufferSnapshot>>>, // buffer_id -> server_id -> vec of snapshots
environment: Option<Model<ProjectEnvironment>>,
supplementary_language_servers:
HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
languages: Arc<LanguageRegistry>,
language_servers: HashMap<LanguageServerId, LanguageServerState>,
language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
last_workspace_edits_by_language_server: HashMap<LanguageServerId, ProjectTransaction>,
language_server_watched_paths: HashMap<LanguageServerId, HashMap<WorktreeId, GlobSet>>,
language_server_watcher_registrations:
HashMap<LanguageServerId, HashMap<String, Vec<FileSystemWatcher>>>,
active_entry: Option<ProjectEntryId>,
_maintain_workspace_config: Task<Result<()>>,
_maintain_buffer_languages: Task<()>,
@ -177,6 +122,8 @@ pub struct LspStore {
)>,
>,
>,
yarn: Model<YarnPathStore>,
_subscription: gpui::Subscription,
}
pub enum LspStoreEvent {
@ -262,53 +209,17 @@ impl LspStore {
client.add_model_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
}
pub fn as_remote(&self) -> Option<&RemoteLspStore> {
match &self.mode {
LspStoreMode::Remote(remote_lsp_store) => Some(remote_lsp_store),
_ => None,
}
}
pub fn as_ssh(&self) -> Option<&SshLspStore> {
match &self.mode {
LspStoreMode::Ssh(ssh_lsp_store) => Some(ssh_lsp_store),
_ => None,
}
}
pub fn as_local(&self) -> Option<&LocalLspStore> {
match &self.mode {
LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
_ => None,
}
}
pub fn as_local_mut(&mut self) -> Option<&mut LocalLspStore> {
match &mut self.mode {
LspStoreMode::Local(local_lsp_store) => Some(local_lsp_store),
_ => None,
}
}
pub fn upstream_client(&self) -> Option<AnyProtoClient> {
match &self.mode {
LspStoreMode::Ssh(SshLspStore {
upstream_client, ..
})
| LspStoreMode::Remote(RemoteLspStore {
upstream_client, ..
}) => Some(upstream_client.clone()),
LspStoreMode::Local(_) => None,
}
}
pub fn new_local(
#[allow(clippy::too_many_arguments)]
pub fn new(
buffer_store: Model<BufferStore>,
worktree_store: Model<WorktreeStore>,
environment: Model<ProjectEnvironment>,
environment: Option<Model<ProjectEnvironment>>,
languages: Arc<LanguageRegistry>,
http_client: Option<Arc<dyn HttpClient>>,
fs: Arc<dyn Fs>,
downstream_client: Option<AnyProtoClient>,
upstream_client: Option<AnyProtoClient>,
remote_id: Option<u64>,
cx: &mut ModelContext<Self>,
) -> Self {
let yarn = YarnPathStore::new(fs.clone(), cx);
@ -318,85 +229,32 @@ impl LspStore {
.detach();
Self {
mode: LspStoreMode::Local(LocalLspStore {
downstream_client,
upstream_client,
http_client,
fs,
project_id: remote_id.unwrap_or(0),
buffer_store,
worktree_store,
languages: languages.clone(),
environment,
nonce: StdRng::from_entropy().gen(),
buffer_snapshots: Default::default(),
supplementary_language_servers: Default::default(),
language_servers: Default::default(),
language_server_ids: Default::default(),
language_server_statuses: Default::default(),
last_workspace_edits_by_language_server: Default::default(),
language_server_watched_paths: Default::default(),
language_server_watcher_registrations: Default::default(),
environment,
http_client,
fs,
next_diagnostic_group_id: Default::default(),
diagnostic_summaries: Default::default(),
diagnostics: Default::default(),
active_entry: None,
yarn,
_subscription: cx.on_app_quit(|this, cx| {
this.as_local_mut().unwrap().shutdown_language_servers(cx)
}),
}),
downstream_client: None,
project_id: 0,
buffer_store,
worktree_store,
languages: languages.clone(),
language_server_ids: Default::default(),
language_server_statuses: Default::default(),
nonce: StdRng::from_entropy().gen(),
buffer_snapshots: Default::default(),
next_diagnostic_group_id: Default::default(),
diagnostic_summaries: Default::default(),
diagnostics: Default::default(),
active_entry: None,
_maintain_workspace_config: Self::maintain_workspace_config(cx),
_maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
}
}
fn send_lsp_proto_request<R: LspCommand>(
&self,
buffer: Model<Buffer>,
client: AnyProtoClient,
request: R,
cx: &mut ModelContext<'_, LspStore>,
) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
let message = request.to_proto(self.project_id, buffer.read(cx));
cx.spawn(move |this, cx| async move {
let response = client.request(message).await?;
let this = this.upgrade().context("project dropped")?;
request
.response_from_proto(response, this, buffer, cx)
.await
})
}
pub fn new_remote(
buffer_store: Model<BufferStore>,
worktree_store: Model<WorktreeStore>,
languages: Arc<LanguageRegistry>,
upstream_client: AnyProtoClient,
project_id: u64,
cx: &mut ModelContext<Self>,
) -> Self {
cx.subscribe(&buffer_store, Self::on_buffer_store_event)
.detach();
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
.detach();
Self {
mode: LspStoreMode::Remote(RemoteLspStore { upstream_client }),
downstream_client: None,
project_id,
buffer_store,
worktree_store,
languages: languages.clone(),
language_server_ids: Default::default(),
language_server_statuses: Default::default(),
nonce: StdRng::from_entropy().gen(),
buffer_snapshots: Default::default(),
next_diagnostic_group_id: Default::default(),
diagnostic_summaries: Default::default(),
diagnostics: Default::default(),
active_entry: None,
_maintain_workspace_config: Self::maintain_workspace_config(cx),
_maintain_buffer_languages: Self::maintain_buffer_languages(languages.clone(), cx),
_subscription: cx.on_app_quit(Self::shutdown_language_servers),
}
}
@ -636,6 +494,27 @@ impl LspStore {
self.active_entry = active_entry;
}
fn shutdown_language_servers(
&mut self,
_cx: &mut ModelContext<Self>,
) -> impl Future<Output = ()> {
let shutdown_futures = self
.language_servers
.drain()
.map(|(_, server_state)| async {
use LanguageServerState::*;
match server_state {
Running { server, .. } => server.shutdown()?.await,
Starting(task) => task.await?.shutdown()?.await,
}
})
.collect::<Vec<_>>();
async move {
futures::future::join_all(shutdown_futures).await;
}
}
pub(crate) fn send_diagnostic_summaries(
&self,
worktree: &mut Worktree,
@ -668,11 +547,9 @@ impl LspStore {
<R::LspRequest as lsp::request::Request>::Params: Send,
{
let buffer = buffer_handle.read(cx);
if let Some(upstream_client) = self.upstream_client() {
return self.send_lsp_proto_request(buffer_handle, upstream_client, request, cx);
if self.upstream_client.is_some() {
return self.send_lsp_proto_request(buffer_handle, self.project_id, request, cx);
}
let language_server = match server {
LanguageServerToQuery::Primary => {
match self.primary_language_server_for_buffer(buffer, cx) {
@ -758,6 +635,26 @@ impl LspStore {
Task::ready(Ok(Default::default()))
}
fn send_lsp_proto_request<R: LspCommand>(
&self,
buffer: Model<Buffer>,
project_id: u64,
request: R,
cx: &mut ModelContext<'_, Self>,
) -> Task<anyhow::Result<<R as LspCommand>::Response>> {
let Some(upstream_client) = self.upstream_client.clone() else {
return Task::ready(Err(anyhow!("disconnected before completing request")));
};
let message = request.to_proto(project_id, buffer.read(cx));
cx.spawn(move |this, cx| async move {
let response = upstream_client.request(message).await?;
let this = this.upgrade().context("project dropped")?;
request
.response_from_proto(response, this, buffer, cx)
.await
})
}
pub async fn execute_code_actions_on_servers(
this: &WeakModel<LspStore>,
adapters_and_servers: &Vec<(Arc<CachedLspAdapter>, Arc<LanguageServer>)>,
@ -805,10 +702,8 @@ impl LspStore {
if let Some(command) = action.lsp_action.command {
this.update(cx, |this, _| {
if let LspStoreMode::Local(mode) = &mut this.mode {
mode.last_workspace_edits_by_language_server
this.last_workspace_edits_by_language_server
.remove(&language_server.server_id());
}
})?;
language_server
@ -820,14 +715,12 @@ impl LspStore {
.await?;
this.update(cx, |this, _| {
if let LspStoreMode::Local(mode) = &mut this.mode {
project_transaction.0.extend(
mode.last_workspace_edits_by_language_server
this.last_workspace_edits_by_language_server
.remove(&language_server.server_id())
.unwrap_or_default()
.0,
)
}
})?;
}
}
@ -860,7 +753,7 @@ impl LspStore {
push_to_history: bool,
cx: &mut ModelContext<Self>,
) -> Task<Result<ProjectTransaction>> {
if let Some(upstream_client) = self.upstream_client() {
if let Some(upstream_client) = self.upstream_client.clone() {
let request = proto::ApplyCodeAction {
project_id: self.project_id,
buffer_id: buffer_handle.read(cx).remote_id().into(),
@ -909,9 +802,7 @@ impl LspStore {
if let Some(command) = action.lsp_action.command {
this.update(&mut cx, |this, _| {
this.as_local_mut()
.unwrap()
.last_workspace_edits_by_language_server
this.last_workspace_edits_by_language_server
.remove(&lang_server.server_id());
})?;
@ -929,9 +820,7 @@ impl LspStore {
}
return this.update(&mut cx, |this, _| {
this.as_local_mut()
.unwrap()
.last_workspace_edits_by_language_server
this.last_workspace_edits_by_language_server
.remove(&lang_server.server_id())
.unwrap_or_default()
});
@ -949,7 +838,7 @@ impl LspStore {
server_id: LanguageServerId,
cx: &mut ModelContext<Self>,
) -> Task<anyhow::Result<InlayHint>> {
if let Some(upstream_client) = self.upstream_client() {
if let Some(upstream_client) = self.upstream_client.clone() {
let request = proto::ResolveInlayHint {
project_id: self.project_id,
buffer_id: buffer_handle.read(cx).remote_id().into(),
@ -1027,7 +916,7 @@ impl LspStore {
.map(|(_, server)| LanguageServerToQuery::Other(server.server_id()))
.next()
.or_else(|| {
self.upstream_client()
self.upstream_client
.is_some()
.then_some(LanguageServerToQuery::Primary)
})
@ -1060,7 +949,7 @@ impl LspStore {
trigger: String,
cx: &mut ModelContext<Self>,
) -> Task<Result<Option<Transaction>>> {
if let Some(client) = self.upstream_client() {
if let Some(client) = self.upstream_client.clone() {
let request = proto::OnTypeFormatting {
project_id: self.project_id,
buffer_id: buffer.read(cx).remote_id().into(),
@ -1210,7 +1099,7 @@ impl LspStore {
range: Range<Anchor>,
cx: &mut ModelContext<Self>,
) -> Task<Vec<CodeAction>> {
if let Some(upstream_client) = self.upstream_client() {
if let Some(upstream_client) = self.upstream_client.as_ref() {
let request_task = upstream_client.request(proto::MultiLspQuery {
buffer_id: buffer_handle.read(cx).remote_id().into(),
version: serialize_version(&buffer_handle.read(cx).version()),
@ -1290,10 +1179,10 @@ impl LspStore {
) -> Task<Result<Vec<Completion>>> {
let language_registry = self.languages.clone();
if let Some(upstream_client) = self.upstream_client() {
if let Some(_) = self.upstream_client.clone() {
let task = self.send_lsp_proto_request(
buffer.clone(),
upstream_client,
self.project_id,
GetCompletions { position, context },
cx,
);
@ -1384,7 +1273,7 @@ impl LspStore {
completions: Arc<RwLock<Box<[Completion]>>>,
cx: &mut ModelContext<Self>,
) -> Task<Result<bool>> {
let client = self.upstream_client();
let client = self.upstream_client.clone();
let language_registry = self.languages.clone();
let project_id = self.project_id;
@ -1593,7 +1482,7 @@ impl LspStore {
let buffer = buffer_handle.read(cx);
let buffer_id = buffer.remote_id();
if let Some(client) = self.upstream_client() {
if let Some(client) = self.upstream_client.clone() {
let project_id = self.project_id;
cx.spawn(move |_, mut cx| async move {
let response = client
@ -1709,7 +1598,7 @@ impl LspStore {
let buffer_id = buffer.remote_id().into();
let lsp_request = InlayHints { range };
if let Some(client) = self.upstream_client() {
if let Some(client) = self.upstream_client.clone() {
let request = proto::InlayHints {
project_id: self.project_id,
buffer_id,
@ -1759,7 +1648,7 @@ impl LspStore {
) -> Task<Vec<SignatureHelp>> {
let position = position.to_point_utf16(buffer.read(cx));
if let Some(client) = self.upstream_client() {
if let Some(client) = self.upstream_client.clone() {
let request_task = client.request(proto::MultiLspQuery {
buffer_id: buffer.read(cx).remote_id().into(),
version: serialize_version(&buffer.read(cx).version()),
@ -1831,7 +1720,7 @@ impl LspStore {
position: PointUtf16,
cx: &mut ModelContext<Self>,
) -> Task<Vec<Hover>> {
if let Some(client) = self.upstream_client() {
if let Some(client) = self.upstream_client.clone() {
let request_task = client.request(proto::MultiLspQuery {
buffer_id: buffer.read(cx).remote_id().into(),
version: serialize_version(&buffer.read(cx).version()),
@ -1905,7 +1794,7 @@ impl LspStore {
pub fn symbols(&self, query: &str, cx: &mut ModelContext<Self>) -> Task<Result<Vec<Symbol>>> {
let language_registry = self.languages.clone();
if let Some(upstream_client) = self.upstream_client().as_ref() {
if let Some(upstream_client) = self.upstream_client.as_ref() {
let request = upstream_client.request(proto::GetProjectSymbols {
project_id: self.project_id,
query: query.to_string(),
@ -1952,8 +1841,7 @@ impl LspStore {
}
let worktree_abs_path = worktree.abs_path().clone();
let (lsp_adapter, language, server) =
match self.as_local().unwrap().language_servers.get(server_id) {
let (lsp_adapter, language, server) = match self.language_servers.get(server_id) {
Some(LanguageServerState::Running {
adapter,
language,
@ -2264,7 +2152,7 @@ impl LspStore {
.worktree_store
.read(cx)
.worktree_for_id(*worktree_id, cx)?;
let state = this.as_local()?.language_servers.get(server_id)?;
let state = this.language_servers.get(server_id)?;
let delegate = ProjectLspAdapterDelegate::new(this, &worktree, cx);
match state {
LanguageServerState::Starting(_) => None,
@ -2330,7 +2218,7 @@ impl LspStore {
language,
server,
..
}) = self.as_local()?.language_servers.get(id)
}) = self.language_servers.get(id)
{
return Some((adapter, language, server));
}
@ -2357,17 +2245,11 @@ impl LspStore {
self.language_server_ids
.remove(&(id_to_remove, server_name));
self.language_server_statuses.remove(&server_id_to_remove);
if let Some(local_lsp_store) = self.as_local_mut() {
local_lsp_store
.language_server_watched_paths
self.language_server_watched_paths
.remove(&server_id_to_remove);
local_lsp_store
.last_workspace_edits_by_language_server
self.last_workspace_edits_by_language_server
.remove(&server_id_to_remove);
local_lsp_store
.language_servers
.remove(&server_id_to_remove);
}
self.language_servers.remove(&server_id_to_remove);
cx.emit(LspStoreEvent::LanguageServerRemoved(server_id_to_remove));
}
}
@ -2463,7 +2345,7 @@ impl LspStore {
let server = self
.language_server_ids
.get(&(worktree_id, adapter.name.clone()))
.and_then(|id| self.as_local()?.language_servers.get(id))
.and_then(|id| self.language_servers.get(id))
.and_then(|server_state| {
if let LanguageServerState::Running { server, .. } = server_state {
Some(server.clone())
@ -2659,7 +2541,7 @@ impl LspStore {
symbol: &Symbol,
cx: &mut ModelContext<Self>,
) -> Task<Result<Model<Buffer>>> {
if let Some(client) = self.upstream_client() {
if let Some(client) = self.upstream_client.clone() {
let request = client.request(proto::OpenBufferForSymbol {
project_id: self.project_id,
symbol: Some(Self::serialize_symbol(symbol)),
@ -2727,7 +2609,7 @@ impl LspStore {
let p = abs_path.clone();
let yarn_worktree = this
.update(&mut cx, move |this, cx| {
this.as_local().unwrap().yarn.update(cx, |_, cx| {
this.yarn.update(cx, |_, cx| {
cx.spawn(|this, mut cx| async move {
let t = this
.update(&mut cx, |this, cx| {
@ -2877,7 +2759,7 @@ impl LspStore {
<R::LspRequest as lsp::request::Request>::Result: Send,
<R::LspRequest as lsp::request::Request>::Params: Send,
{
debug_assert!(self.upstream_client().is_none());
debug_assert!(self.upstream_client.is_none());
let snapshot = buffer.read(cx).snapshot();
let scope = position.and_then(|position| snapshot.language_scope_at(position));
@ -3306,9 +3188,7 @@ impl LspStore {
simulate_disk_based_diagnostics_completion,
adapter,
..
}) = self
.as_local_mut()
.and_then(|local_store| local_store.language_servers.get_mut(&language_server_id))
}) = self.language_servers.get_mut(&language_server_id)
else {
return;
};
@ -3329,9 +3209,8 @@ impl LspStore {
if let Some(LanguageServerState::Running {
simulate_disk_based_diagnostics_completion,
..
}) = this.as_local_mut().and_then(|local_store| {
local_store.language_servers.get_mut(&language_server_id)
}) {
}) = this.language_servers.get_mut(&language_server_id)
{
*simulate_disk_based_diagnostics_completion = None;
}
})
@ -3357,24 +3236,21 @@ impl LspStore {
language_server_id: LanguageServerId,
cx: &mut ModelContext<Self>,
) {
let worktrees = self.worktree_store.read(cx).worktrees().collect::<Vec<_>>();
let local_lsp_store = self.as_local_mut().unwrap();
let Some(watchers) = local_lsp_store
let Some(watchers) = self
.language_server_watcher_registrations
.get(&language_server_id)
else {
return;
};
let watched_paths = local_lsp_store
let watched_paths = self
.language_server_watched_paths
.entry(language_server_id)
.or_default();
let mut builders = HashMap::default();
for watcher in watchers.values().flatten() {
for worktree in worktrees.iter() {
for worktree in self.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
let glob_is_inside_worktree = worktree.update(cx, |tree, _| {
if let Some(abs_path) = tree.abs_path().to_str() {
let relative_glob_pattern = match &watcher.glob_pattern {
@ -3428,21 +3304,13 @@ impl LspStore {
}
pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
if let Some(local_lsp_store) = self.as_local() {
if let Some(LanguageServerState::Running { server, .. }) =
local_lsp_store.language_servers.get(&id)
{
if let Some(LanguageServerState::Running { server, .. }) = self.language_servers.get(&id) {
Some(server.clone())
} else if let Some((_, server)) =
local_lsp_store.supplementary_language_servers.get(&id)
{
} else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
Some(Arc::clone(server))
} else {
None
}
} else {
None
}
}
async fn on_lsp_workspace_edit(
@ -3470,9 +3338,7 @@ impl LspStore {
.log_err();
this.update(&mut cx, |this, _| {
if let Some(transaction) = transaction {
this.as_local_mut()
.unwrap()
.last_workspace_edits_by_language_server
this.last_workspace_edits_by_language_server
.insert(server_id, transaction);
}
})?;
@ -3657,8 +3523,7 @@ impl LspStore {
params: DidChangeWatchedFilesRegistrationOptions,
cx: &mut ModelContext<Self>,
) {
if let Some(local) = self.as_local_mut() {
let registrations = local
let registrations = self
.language_server_watcher_registrations
.entry(language_server_id)
.or_default();
@ -3667,7 +3532,6 @@ impl LspStore {
self.rebuild_watched_paths(language_server_id, cx);
}
}
fn on_lsp_unregister_did_change_watched_files(
&mut self,
@ -3675,8 +3539,7 @@ impl LspStore {
registration_id: &str,
cx: &mut ModelContext<Self>,
) {
if let Some(local) = self.as_local_mut() {
let registrations = local
let registrations = self
.language_server_watcher_registrations
.entry(language_server_id)
.or_default();
@ -3697,7 +3560,6 @@ impl LspStore {
self.rebuild_watched_paths(language_server_id, cx);
}
}
#[allow(clippy::type_complexity)]
pub(crate) fn edits_from_lsp(
@ -4213,7 +4075,6 @@ impl LspStore {
language: Arc<Language>,
cx: &mut ModelContext<Self>,
) {
if self.mode.is_local() {
if adapter.reinstall_attempt_count.load(SeqCst) > MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
return;
}
@ -4229,12 +4090,9 @@ impl LspStore {
let stderr_capture = Arc::new(Mutex::new(Some(String::new())));
let lsp_adapter_delegate = ProjectLspAdapterDelegate::new(self, worktree_handle, cx);
let cli_environment = self
.as_local()
.unwrap()
.environment
.read(cx)
.get_cli_environment();
.as_ref()
.and_then(|environment| environment.read(cx).get_cli_environment());
let pending_server = match self.languages.create_pending_language_server(
stderr_capture.clone(),
language.clone(),
@ -4293,13 +4151,10 @@ impl LspStore {
let this = this.upgrade()?;
let container_dir = container_dir?;
let attempt_count =
adapter.reinstall_attempt_count.fetch_add(1, SeqCst);
let attempt_count = adapter.reinstall_attempt_count.fetch_add(1, SeqCst);
if attempt_count >= MAX_SERVER_REINSTALL_ATTEMPT_COUNT {
let max = MAX_SERVER_REINSTALL_ATTEMPT_COUNT;
log::error!(
"Hit {max} reinstallation attempts for {server_name:?}"
);
log::error!("Hit {max} reinstallation attempts for {server_name:?}");
return None;
}
@ -4332,14 +4187,8 @@ impl LspStore {
})
});
self.as_local_mut()
.unwrap()
.language_servers
.insert(server_id, state);
self.language_servers.insert(server_id, state);
self.language_server_ids.insert(key, server_id);
} else if self.mode.is_ssh() {
// TODO ssh
}
}
#[allow(clippy::too_many_arguments)]
@ -4393,8 +4242,7 @@ impl LspStore {
) -> Option<Task<()>> {
log::info!("beginning to reinstall server");
if let Some(local) = self.as_local_mut() {
let existing_server = match local.language_servers.remove(&server_id) {
let existing_server = match self.language_servers.remove(&server_id) {
Some(LanguageServerState::Running { server, .. }) => Some(server),
_ => None,
};
@ -4427,22 +4275,11 @@ impl LspStore {
this.update(&mut cx, |this, cx| {
for worktree in this.worktree_store.read(cx).worktrees().collect::<Vec<_>>() {
this.start_language_server(
&worktree,
adapter.clone(),
language.clone(),
cx,
);
this.start_language_server(&worktree, adapter.clone(), language.clone(), cx);
}
})
.ok();
}))
} else if let Some(_ssh_store) = self.as_ssh() {
// TODO
None
} else {
None
}
}
async fn shutdown_language_server(
@ -4490,7 +4327,6 @@ impl LspStore {
cx: &mut ModelContext<Self>,
) -> Task<Vec<WorktreeId>> {
let key = (worktree_id, adapter_name);
if self.mode.is_local() {
if let Some(server_id) = self.language_server_ids.remove(&key) {
let name = key.1 .0;
log::info!("stopping language server {name}");
@ -4551,18 +4387,11 @@ impl LspStore {
});
}
self.as_local_mut()
.unwrap()
.language_server_watched_paths
.remove(&server_id);
self.language_server_watched_paths.remove(&server_id);
self.language_server_statuses.remove(&server_id);
cx.notify();
let server_state = self
.as_local_mut()
.unwrap()
.language_servers
.remove(&server_id);
let server_state = self.language_servers.remove(&server_id);
cx.emit(LspStoreEvent::LanguageServerRemoved(server_id));
cx.spawn(move |_, cx| async move {
Self::shutdown_language_server(server_state, name, cx).await;
@ -4571,12 +4400,6 @@ impl LspStore {
} else {
Task::ready(Vec::new())
}
} else if self.mode.is_ssh() {
// TODO ssh
Task::ready(Vec::new())
} else {
Task::ready(Vec::new())
}
}
pub fn restart_language_servers_for_buffers(
@ -4584,7 +4407,7 @@ impl LspStore {
buffers: impl IntoIterator<Item = Model<Buffer>>,
cx: &mut ModelContext<Self>,
) {
if let Some(client) = self.upstream_client() {
if let Some(client) = self.upstream_client.clone() {
let request = client.request(proto::RestartLanguageServers {
project_id: self.project_id,
buffer_ids: buffers
@ -5369,8 +5192,7 @@ impl LspStore {
// Update language_servers collection with Running variant of LanguageServerState
// indicating that the server is up and running and ready
if let Some(local) = self.as_local_mut() {
local.language_servers.insert(
self.language_servers.insert(
server_id,
LanguageServerState::Running {
adapter: adapter.clone(),
@ -5379,7 +5201,6 @@ impl LspStore {
simulate_disk_based_diagnostics_completion: None,
},
);
}
self.language_server_statuses.insert(
server_id,
@ -5531,14 +5352,12 @@ impl LspStore {
) -> impl Iterator<Item = (&'a Arc<CachedLspAdapter>, &'a Arc<LanguageServer>)> {
self.language_server_ids_for_buffer(buffer, cx)
.into_iter()
.filter_map(
|server_id| match self.as_local()?.language_servers.get(&server_id)? {
.filter_map(|server_id| match self.language_servers.get(&server_id)? {
LanguageServerState::Running {
adapter, server, ..
} => Some((adapter, server)),
_ => None,
},
)
})
}
pub(crate) fn cancel_language_server_work_for_buffers(
@ -5576,46 +5395,37 @@ impl LspStore {
server: Arc<LanguageServer>,
cx: &mut ModelContext<Self>,
) {
if let Some(local) = self.as_local_mut() {
local
.supplementary_language_servers
self.supplementary_language_servers
.insert(id, (name, server));
cx.emit(LspStoreEvent::LanguageServerAdded(id));
}
}
pub fn unregister_supplementary_language_server(
&mut self,
id: LanguageServerId,
cx: &mut ModelContext<Self>,
) {
if let Some(local) = self.as_local_mut() {
local.supplementary_language_servers.remove(&id);
self.supplementary_language_servers.remove(&id);
cx.emit(LspStoreEvent::LanguageServerRemoved(id));
}
}
pub fn supplementary_language_servers(
&self,
) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
self.as_local().into_iter().flat_map(|local| {
local
.supplementary_language_servers
) -> impl '_ + Iterator<Item = (&LanguageServerId, &LanguageServerName)> {
self.supplementary_language_servers
.iter()
.map(|(id, (name, _))| (*id, name.clone()))
})
.map(|(id, (name, _))| (id, name))
}
pub fn language_server_adapter_for_id(
&self,
id: LanguageServerId,
) -> Option<Arc<CachedLspAdapter>> {
self.as_local()
.and_then(|local| local.language_servers.get(&id))
.and_then(|language_server_state| match language_server_state {
LanguageServerState::Running { adapter, .. } => Some(adapter.clone()),
_ => None,
})
if let Some(LanguageServerState::Running { adapter, .. }) = self.language_servers.get(&id) {
Some(adapter.clone())
} else {
None
}
}
pub fn update_local_worktree_language_servers(
@ -5641,11 +5451,10 @@ impl LspStore {
let abs_path = worktree_handle.read(cx).abs_path();
for server_id in &language_server_ids {
if let Some(local) = self.as_local() {
if let Some(LanguageServerState::Running { server, .. }) =
local.language_servers.get(server_id)
self.language_servers.get(server_id)
{
if let Some(watched_paths) = local
if let Some(watched_paths) = self
.language_server_watched_paths
.get(&server_id)
.and_then(|paths| paths.get(&worktree_id))
@ -5680,7 +5489,6 @@ impl LspStore {
}
}
}
}
pub(crate) fn cancel_language_server_work(
&mut self,
@ -5689,9 +5497,7 @@ impl LspStore {
_cx: &mut ModelContext<Self>,
) {
let status = self.language_server_statuses.get(&server_id);
let server = self
.as_local()
.and_then(|local| local.language_servers.get(&server_id));
let server = self.language_servers.get(&server_id);
if let Some((server, status)) = server.zip(status) {
if let LanguageServerState::Running { server, .. } = server {
for (token, progress) in &status.pending_work {
@ -5794,8 +5600,7 @@ impl LspStore {
language_server: Arc<LanguageServer>,
cx: &mut AsyncAppContext,
) -> Result<ProjectTransaction> {
let fs = this.read_with(cx, |this, _| this.as_local().unwrap().fs.clone())?;
let fs = this.update(cx, |this, _| this.fs.clone())?;
let mut operations = Vec::new();
if let Some(document_changes) = edit.document_changes {
match document_changes {
@ -6314,10 +6119,7 @@ impl ProjectLspAdapterDelegate {
) -> Arc<Self> {
let worktree_id = worktree.read(cx).id();
let worktree_abs_path = worktree.read(cx).abs_path();
let load_shell_env_task = if let Some(environment) =
&lsp_store.as_local().map(|local| local.environment.clone())
{
let load_shell_env_task = if let Some(environment) = &lsp_store.environment {
environment.update(cx, |env, cx| {
env.get_environment(Some(worktree_id), Some(worktree_abs_path), cx)
})
@ -6325,23 +6127,14 @@ impl ProjectLspAdapterDelegate {
Task::ready(None).shared()
};
let Some(http_client) = lsp_store
.as_local()
.and_then(|local| local.http_client.clone())
else {
let Some(http_client) = lsp_store.http_client.clone() else {
panic!("ProjectLspAdapterDelegate cannot be constructedd on an ssh-remote yet")
};
let fs = lsp_store
.as_local()
.expect("ProjectLspAdapterDelegate cannot be constructedd on an ssh-remote yet")
.fs
.clone();
Arc::new(Self {
lsp_store: cx.weak_model(),
worktree: worktree.read(cx).snapshot(),
fs,
fs: lsp_store.fs.clone(),
http_client,
language_registry: lsp_store.languages.clone(),
load_shell_env_task,

View File

@ -643,13 +643,16 @@ impl Project {
let environment = ProjectEnvironment::new(&worktree_store, env, cx);
let lsp_store = cx.new_model(|cx| {
LspStore::new_local(
LspStore::new(
buffer_store.clone(),
worktree_store.clone(),
environment.clone(),
Some(environment.clone()),
languages.clone(),
Some(client.http_client()),
fs.clone(),
None,
None,
None,
cx,
)
});
@ -709,90 +712,17 @@ impl Project {
fs: Arc<dyn Fs>,
cx: &mut AppContext,
) -> Model<Self> {
cx.new_model(|cx: &mut ModelContext<Self>| {
let (tx, rx) = mpsc::unbounded();
cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
.detach();
let tasks = Inventory::new(cx);
let global_snippets_dir = paths::config_dir().join("snippets");
let snippets =
SnippetProvider::new(fs.clone(), BTreeSet::from_iter([global_snippets_dir]), cx);
let worktree_store = cx.new_model(|_| {
let mut worktree_store = WorktreeStore::new(false, fs.clone());
worktree_store.set_upstream_client(ssh.clone().into());
worktree_store
});
cx.subscribe(&worktree_store, Self::on_worktree_store_event)
.detach();
let buffer_store =
cx.new_model(|cx| BufferStore::new(worktree_store.clone(), None, cx));
cx.subscribe(&buffer_store, Self::on_buffer_store_event)
.detach();
let settings_observer = cx.new_model(|cx| {
SettingsObserver::new_ssh(ssh.clone().into(), worktree_store.clone(), cx)
});
let environment = ProjectEnvironment::new(&worktree_store, None, cx);
let lsp_store = cx.new_model(|cx| {
LspStore::new_remote(
buffer_store.clone(),
worktree_store.clone(),
languages.clone(),
ssh.clone().into(),
0,
cx,
)
});
cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
let this = Self {
buffer_ordered_messages_tx: tx,
collaborators: Default::default(),
worktree_store,
buffer_store,
lsp_store,
current_lsp_settings: ProjectSettings::get_global(cx).lsp.clone(),
join_project_response_message_id: 0,
client_state: ProjectClientState::Local,
client_subscriptions: Vec::new(),
_subscriptions: vec![
cx.observe_global::<SettingsStore>(Self::on_settings_changed),
cx.on_release(Self::release),
],
active_entry: None,
snippets,
languages,
client,
user_store,
settings_observer,
fs,
ssh_session: Some(ssh.clone()),
buffers_needing_diff: Default::default(),
git_diff_debouncer: DebouncedDelay::new(),
terminals: Terminals {
local_handles: Vec::new(),
},
node: Some(node),
default_prettier: DefaultPrettier::default(),
prettiers_per_worktree: HashMap::default(),
prettier_instances: HashMap::default(),
tasks,
hosted_project_id: None,
dev_server_project_id: None,
search_history: Self::new_search_history(),
environment,
remotely_created_buffers: Default::default(),
last_formatting_failure: None,
buffers_being_formatted: Default::default(),
search_included_history: Self::new_search_history(),
search_excluded_history: Self::new_search_history(),
};
let this = Self::local(client, node, user_store, languages, fs, None, cx);
this.update(cx, |this, cx| {
let client: AnyProtoClient = ssh.clone().into();
this.worktree_store.update(cx, |store, _cx| {
store.set_upstream_client(client.clone());
});
this.settings_observer = cx.new_model(|cx| {
SettingsObserver::new_ssh(ssh.clone().into(), this.worktree_store.clone(), cx)
});
ssh.subscribe_to_entity(SSH_PROJECT_ID, &cx.handle());
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.buffer_store);
ssh.subscribe_to_entity(SSH_PROJECT_ID, &this.worktree_store);
@ -805,8 +735,9 @@ impl Project {
LspStore::init(&client);
SettingsObserver::init(&client);
this.ssh_session = Some(ssh);
});
this
})
}
pub async fn remote(
@ -889,12 +820,16 @@ impl Project {
cx.new_model(|cx| BufferStore::new(worktree_store.clone(), Some(remote_id), cx))?;
let lsp_store = cx.new_model(|cx| {
let mut lsp_store = LspStore::new_remote(
let mut lsp_store = LspStore::new(
buffer_store.clone(),
worktree_store.clone(),
None,
languages.clone(),
client.clone().into(),
remote_id,
Some(client.http_client()),
fs.clone(),
None,
Some(client.clone().into()),
Some(remote_id),
cx,
);
lsp_store.set_language_server_statuses_from_proto(response.payload.language_servers);
@ -4850,7 +4785,7 @@ impl Project {
pub fn supplementary_language_servers<'a>(
&'a self,
cx: &'a AppContext,
) -> impl '_ + Iterator<Item = (LanguageServerId, LanguageServerName)> {
) -> impl '_ + Iterator<Item = (&'a LanguageServerId, &'a LanguageServerName)> {
self.lsp_store.read(cx).supplementary_language_servers()
}

View File

@ -57,17 +57,18 @@ impl HeadlessProject {
});
let environment = project::ProjectEnvironment::new(&worktree_store, None, cx);
let lsp_store = cx.new_model(|cx| {
let mut lsp_store = LspStore::new_local(
LspStore::new(
buffer_store.clone(),
worktree_store.clone(),
environment,
Some(environment),
languages,
None,
fs.clone(),
Some(session.clone().into()),
None,
Some(0),
cx,
);
lsp_store.shared(SSH_PROJECT_ID, session.clone().into(), cx);
lsp_store
)
});
let client: AnyProtoClient = session.clone().into();