ssh remoting: Do not double-register LspAdapters (#18132)

This fixes the bug with hover tooltips appearing multiple times.

Turns out everytime we receive the `CreateLanguageServer` message we'd
add a new adapter but only have a single server running for all of them.

And we send a `CreateLanguageServer` message everytime you open a
buffer.

What this does is to only add a new adapter if it hasn't already been
registered, which is also what we do locally.


Release Notes:

- N/A
This commit is contained in:
Thorsten Ball 2024-09-20 14:35:45 +02:00 committed by GitHub
parent ca033e6475
commit 90a12f5564
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 24 deletions

View file

@ -326,13 +326,43 @@ impl LanguageRegistry {
Some(load_lsp_adapter()) Some(load_lsp_adapter())
} }
pub fn register_lsp_adapter(&self, language_name: LanguageName, adapter: Arc<dyn LspAdapter>) { pub fn register_lsp_adapter(
&self,
language_name: LanguageName,
adapter: Arc<dyn LspAdapter>,
) -> Arc<CachedLspAdapter> {
let cached = CachedLspAdapter::new(adapter);
self.state self.state
.write() .write()
.lsp_adapters .lsp_adapters
.entry(language_name) .entry(language_name)
.or_default() .or_default()
.push(CachedLspAdapter::new(adapter)); .push(cached.clone());
cached
}
pub fn get_or_register_lsp_adapter(
&self,
language_name: LanguageName,
server_name: LanguageServerName,
build_adapter: impl FnOnce() -> Arc<dyn LspAdapter> + 'static,
) -> Arc<CachedLspAdapter> {
let registered = self
.state
.write()
.lsp_adapters
.entry(language_name.clone())
.or_default()
.iter()
.find(|cached_adapter| cached_adapter.name == server_name)
.cloned();
if let Some(found) = registered {
found
} else {
let adapter = build_adapter();
self.register_lsp_adapter(language_name, adapter)
}
} }
/// Register a fake language server and adapter /// Register a fake language server and adapter

View file

@ -4475,7 +4475,7 @@ impl LspStore {
mut cx: AsyncAppContext, mut cx: AsyncAppContext,
) -> Result<proto::Ack> { ) -> Result<proto::Ack> {
let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id); let worktree_id = WorktreeId::from_proto(envelope.payload.worktree_id);
let name = LanguageServerName::from_proto(envelope.payload.name); let server_name = LanguageServerName::from_proto(envelope.payload.name);
let binary = envelope let binary = envelope
.payload .payload
@ -4494,6 +4494,14 @@ impl LspStore {
let matcher: LanguageMatcher = serde_json::from_str(&language.matcher)?; let matcher: LanguageMatcher = serde_json::from_str(&language.matcher)?;
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
let Some(worktree) = this
.worktree_store
.read(cx)
.worktree_for_id(worktree_id, cx)
else {
return Err(anyhow!("worktree not found"));
};
this.languages this.languages
.register_language(language_name.clone(), None, matcher.clone(), { .register_language(language_name.clone(), None, matcher.clone(), {
let language_name = language_name.clone(); let language_name = language_name.clone();
@ -4513,28 +4521,20 @@ impl LspStore {
.spawn(this.languages.language_for_name(language_name.0.as_ref())) .spawn(this.languages.language_for_name(language_name.0.as_ref()))
.detach(); .detach();
let adapter = Arc::new(SshLspAdapter::new( let adapter = this.languages.get_or_register_lsp_adapter(
name, language_name.clone(),
binary, server_name.clone(),
envelope.payload.initialization_options, || {
envelope.payload.code_action_kinds, Arc::new(SshLspAdapter::new(
)); server_name,
binary,
this.languages envelope.payload.initialization_options,
.register_lsp_adapter(language_name.clone(), adapter.clone()); envelope.payload.code_action_kinds,
let Some(worktree) = this ))
.worktree_store },
.read(cx)
.worktree_for_id(worktree_id, cx)
else {
return Err(anyhow!("worktree not found"));
};
this.start_language_server(
&worktree,
CachedLspAdapter::new(adapter),
language_name,
cx,
); );
this.start_language_server(&worktree, adapter, language_name, cx);
Ok(()) Ok(())
})??; })??;
Ok(proto::Ack {}) Ok(proto::Ack {})