Fix renames over language server for SSH remoting (#17897)

Release Notes:

- ssh remoting: Fix rename over language server

---------

Co-authored-by: Mikayla <mikayla@zed.dev>
Co-authored-by: Max <max@zed.dev>
This commit is contained in:
Conrad Irwin 2024-09-16 16:20:17 -06:00 committed by GitHub
parent 01bb10f518
commit e66ea9e5d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 505 additions and 329 deletions

View file

@ -15,7 +15,7 @@ use gpui::{
use http_client::Url;
use language::{
proto::{deserialize_line_ending, deserialize_version, serialize_version, split_operations},
Buffer, Capability, Event as BufferEvent, File as _, Language, Operation,
Buffer, BufferEvent, Capability, File as _, Language, Operation,
};
use rpc::{proto, AnyProtoClient, ErrorExt as _, TypedEnvelope};
use smol::channel::Receiver;
@ -62,7 +62,7 @@ pub enum BufferStoreEvent {
},
}
#[derive(Default)]
#[derive(Default, Debug)]
pub struct ProjectTransaction(pub HashMap<Model<Buffer>, language::Transaction>);
impl EventEmitter<BufferStoreEvent> for BufferStore {}
@ -1054,7 +1054,11 @@ impl BufferStore {
buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
}
OpenBuffer::Operations(operations) => operations.extend_from_slice(&ops),
OpenBuffer::Weak(_) => {}
OpenBuffer::Weak(buffer) => {
if let Some(buffer) = buffer.upgrade() {
buffer.update(cx, |buffer, cx| buffer.apply_ops(ops, cx))?;
}
}
},
hash_map::Entry::Vacant(e) => {
e.insert(OpenBuffer::Operations(ops));

View file

@ -46,8 +46,8 @@ pub fn lsp_formatting_options(settings: &LanguageSettings) -> lsp::FormattingOpt
}
#[async_trait(?Send)]
pub trait LspCommand: 'static + Sized + Send {
type Response: 'static + Default + Send;
pub trait LspCommand: 'static + Sized + Send + std::fmt::Debug {
type Response: 'static + Default + Send + std::fmt::Debug;
type LspRequest: 'static + Send + lsp::request::Request;
type ProtoRequest: 'static + Send + proto::RequestMessage;
@ -104,72 +104,80 @@ pub trait LspCommand: 'static + Sized + Send {
fn buffer_id_from_proto(message: &Self::ProtoRequest) -> Result<BufferId>;
}
#[derive(Debug)]
pub(crate) struct PrepareRename {
pub position: PointUtf16,
}
#[derive(Debug)]
pub(crate) struct PerformRename {
pub position: PointUtf16,
pub new_name: String,
pub push_to_history: bool,
}
#[derive(Debug)]
pub struct GetDefinition {
pub position: PointUtf16,
}
#[derive(Debug)]
pub(crate) struct GetDeclaration {
pub position: PointUtf16,
}
#[derive(Debug)]
pub(crate) struct GetTypeDefinition {
pub position: PointUtf16,
}
#[derive(Debug)]
pub(crate) struct GetImplementation {
pub position: PointUtf16,
}
#[derive(Debug)]
pub(crate) struct GetReferences {
pub position: PointUtf16,
}
#[derive(Debug)]
pub(crate) struct GetDocumentHighlights {
pub position: PointUtf16,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub(crate) struct GetSignatureHelp {
pub position: PointUtf16,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub(crate) struct GetHover {
pub position: PointUtf16,
}
#[derive(Debug)]
pub(crate) struct GetCompletions {
pub position: PointUtf16,
pub context: CompletionContext,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub(crate) struct GetCodeActions {
pub range: Range<Anchor>,
pub kinds: Option<Vec<lsp::CodeActionKind>>,
}
#[derive(Debug)]
pub(crate) struct OnTypeFormatting {
pub position: PointUtf16,
pub trigger: String,
pub options: lsp::FormattingOptions,
pub push_to_history: bool,
}
#[derive(Debug)]
pub(crate) struct InlayHints {
pub range: Range<Anchor>,
}
#[derive(Debug)]
pub(crate) struct LinkedEditingRange {
pub position: Anchor,
}

View file

@ -36,7 +36,7 @@ impl ExpandedMacro {
self.name.is_empty() && self.expansion.is_empty()
}
}
#[derive(Debug)]
pub struct ExpandMacro {
pub position: PointUtf16,
}

View file

@ -501,15 +501,15 @@ impl LspStore {
fn on_buffer_event(
&mut self,
buffer: Model<Buffer>,
event: &language::Event,
event: &language::BufferEvent,
cx: &mut ModelContext<Self>,
) {
match event {
language::Event::Edited { .. } => {
language::BufferEvent::Edited { .. } => {
self.on_buffer_edited(buffer, cx);
}
language::Event::Saved => {
language::BufferEvent::Saved => {
self.on_buffer_saved(buffer, cx);
}
@ -2930,6 +2930,7 @@ impl LspStore {
})
.map(|(_, server)| server.server_id())
.collect::<Vec<_>>();
let mut response_results = server_ids
.into_iter()
.map(|server_id| {

View file

@ -50,9 +50,9 @@ use language::{
deserialize_anchor, serialize_anchor, serialize_line_ending, serialize_version,
split_operations,
},
Buffer, CachedLspAdapter, Capability, CodeLabel, ContextProvider, DiagnosticEntry, Diff,
Documentation, Event as BufferEvent, File as _, Language, LanguageRegistry, LanguageServerName,
PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped,
Buffer, BufferEvent, CachedLspAdapter, Capability, CodeLabel, ContextProvider, DiagnosticEntry,
Diff, Documentation, File as _, Language, LanguageRegistry, LanguageServerName, PointUtf16,
ToOffset, ToPointUtf16, Transaction, Unclipped,
};
use lsp::{CompletionContext, DocumentHighlightKind, LanguageServer, LanguageServerId};
use lsp_command::*;
@ -799,6 +799,7 @@ impl Project {
client.add_model_message_handler(Self::handle_create_buffer_for_peer);
client.add_model_message_handler(BufferStore::handle_update_buffer_file);
client.add_model_message_handler(BufferStore::handle_update_diff_base);
client.add_model_request_handler(BufferStore::handle_update_buffer);
LspStore::init(&client);
SettingsObserver::init(&client);
@ -1367,7 +1368,13 @@ impl Project {
pub fn replica_id(&self) -> ReplicaId {
match self.client_state {
ProjectClientState::Remote { replica_id, .. } => replica_id,
_ => 0,
_ => {
if self.ssh_session.is_some() {
1
} else {
0
}
}
}
}
@ -1818,6 +1825,15 @@ impl Project {
}
}
pub fn is_via_ssh(&self) -> bool {
match &self.client_state {
ProjectClientState::Local | ProjectClientState::Shared { .. } => {
self.ssh_session.is_some()
}
ProjectClientState::Remote { .. } => false,
}
}
pub fn is_via_collab(&self) -> bool {
match &self.client_state {
ProjectClientState::Local | ProjectClientState::Shared { .. } => false,

View file

@ -315,7 +315,7 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
let project = Project::test(fs.clone(), ["/the-root".as_ref()], cx).await;
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
let mut fake_rust_servers = language_registry.register_fake_lsp_adapter(
let mut fake_rust_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
name: "the-rust-language-server",
@ -335,7 +335,7 @@ async fn test_managing_language_servers(cx: &mut gpui::TestAppContext) {
..Default::default()
},
);
let mut fake_json_servers = language_registry.register_fake_lsp_adapter(
let mut fake_json_servers = language_registry.register_fake_lsp(
"JSON",
FakeLspAdapter {
name: "the-json-language-server",
@ -716,7 +716,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
let project = Project::test(fs.clone(), ["/the-root".as_ref()], cx).await;
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp_adapter(
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
name: "the-language-server",
@ -1125,7 +1125,7 @@ async fn test_disk_based_diagnostics_progress(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp_adapter(
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
disk_based_diagnostics_progress_token: Some(progress_token.into()),
@ -1247,7 +1247,7 @@ async fn test_restarting_server_with_diagnostics_running(cx: &mut gpui::TestAppC
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp_adapter(
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
name: "the-language-server",
@ -1324,8 +1324,7 @@ async fn test_restarting_server_with_diagnostics_published(cx: &mut gpui::TestAp
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers =
language_registry.register_fake_lsp_adapter("Rust", FakeLspAdapter::default());
let mut fake_servers = language_registry.register_fake_lsp("Rust", FakeLspAdapter::default());
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
@ -1404,8 +1403,7 @@ async fn test_restarted_server_reporting_invalid_buffer_version(cx: &mut gpui::T
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers =
language_registry.register_fake_lsp_adapter("Rust", FakeLspAdapter::default());
let mut fake_servers = language_registry.register_fake_lsp("Rust", FakeLspAdapter::default());
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
@ -1445,7 +1443,7 @@ async fn test_cancel_language_server_work(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp_adapter(
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
name: "the-language-server",
@ -1506,14 +1504,14 @@ async fn test_toggling_enable_language_server(cx: &mut gpui::TestAppContext) {
let project = Project::test(fs, ["/dir".as_ref()], cx).await;
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
let mut fake_rust_servers = language_registry.register_fake_lsp_adapter(
let mut fake_rust_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
name: "rust-lsp",
..Default::default()
},
);
let mut fake_js_servers = language_registry.register_fake_lsp_adapter(
let mut fake_js_servers = language_registry.register_fake_lsp(
"JavaScript",
FakeLspAdapter {
name: "js-lsp",
@ -1627,7 +1625,7 @@ async fn test_transforming_diagnostics(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp_adapter(
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
disk_based_diagnostics_sources: vec!["disk".into()],
@ -2049,8 +2047,7 @@ async fn test_edits_from_lsp2_with_past_version(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers =
language_registry.register_fake_lsp_adapter("Rust", FakeLspAdapter::default());
let mut fake_servers = language_registry.register_fake_lsp("Rust", FakeLspAdapter::default());
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/dir/a.rs", cx))
@ -2421,8 +2418,7 @@ async fn test_definition(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers =
language_registry.register_fake_lsp_adapter("Rust", FakeLspAdapter::default());
let mut fake_servers = language_registry.register_fake_lsp("Rust", FakeLspAdapter::default());
let buffer = project
.update(cx, |project, cx| project.open_local_buffer("/dir/b.rs", cx))
@ -2515,7 +2511,7 @@ async fn test_completions_without_edit_ranges(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(typescript_lang());
let mut fake_language_servers = language_registry.register_fake_lsp_adapter(
let mut fake_language_servers = language_registry.register_fake_lsp(
"TypeScript",
FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
@ -2607,7 +2603,7 @@ async fn test_completions_with_carriage_returns(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(typescript_lang());
let mut fake_language_servers = language_registry.register_fake_lsp_adapter(
let mut fake_language_servers = language_registry.register_fake_lsp(
"TypeScript",
FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
@ -2668,7 +2664,7 @@ async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(typescript_lang());
let mut fake_language_servers = language_registry.register_fake_lsp_adapter(
let mut fake_language_servers = language_registry.register_fake_lsp(
"TypeScript",
FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
@ -3310,7 +3306,10 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
assert!(buffer.is_dirty());
assert_eq!(
*events.lock(),
&[language::Event::Edited, language::Event::DirtyChanged]
&[
language::BufferEvent::Edited,
language::BufferEvent::DirtyChanged
]
);
events.lock().clear();
buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), cx);
@ -3319,7 +3318,7 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
// after saving, the buffer is not dirty, and emits a saved event.
buffer1.update(cx, |buffer, cx| {
assert!(!buffer.is_dirty());
assert_eq!(*events.lock(), &[language::Event::Saved]);
assert_eq!(*events.lock(), &[language::BufferEvent::Saved]);
events.lock().clear();
buffer.edit([(1..1, "B")], None, cx);
@ -3333,9 +3332,9 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
assert_eq!(
*events.lock(),
&[
language::Event::Edited,
language::Event::DirtyChanged,
language::Event::Edited,
language::BufferEvent::Edited,
language::BufferEvent::DirtyChanged,
language::BufferEvent::Edited,
],
);
events.lock().clear();
@ -3349,7 +3348,10 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
assert_eq!(
*events.lock(),
&[language::Event::Edited, language::Event::DirtyChanged]
&[
language::BufferEvent::Edited,
language::BufferEvent::DirtyChanged
]
);
// When a file is deleted, the buffer is considered dirty.
@ -3374,8 +3376,8 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
assert_eq!(
*events.lock(),
&[
language::Event::DirtyChanged,
language::Event::FileHandleChanged
language::BufferEvent::DirtyChanged,
language::BufferEvent::FileHandleChanged
]
);
@ -3401,7 +3403,7 @@ async fn test_buffer_is_dirty(cx: &mut gpui::TestAppContext) {
.await
.unwrap();
cx.executor().run_until_parked();
assert_eq!(*events.lock(), &[language::Event::FileHandleChanged]);
assert_eq!(*events.lock(), &[language::BufferEvent::FileHandleChanged]);
cx.update(|cx| assert!(buffer3.read(cx).is_dirty()));
}
@ -3809,7 +3811,7 @@ async fn test_rename(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(rust_lang());
let mut fake_servers = language_registry.register_fake_lsp_adapter(
let mut fake_servers = language_registry.register_fake_lsp(
"Rust",
FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
@ -4696,50 +4698,52 @@ async fn test_multiple_language_server_hovers(cx: &mut gpui::TestAppContext) {
"ESLintServer",
"NoHoverCapabilitiesServer",
];
let mut fake_tsx_language_servers = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[0],
capabilities: lsp::ServerCapabilities {
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
let mut language_servers = [
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[0],
capabilities: lsp::ServerCapabilities {
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
let _a = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[1],
capabilities: lsp::ServerCapabilities {
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
),
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[1],
capabilities: lsp::ServerCapabilities {
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
let _b = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[2],
capabilities: lsp::ServerCapabilities {
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
),
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[2],
capabilities: lsp::ServerCapabilities {
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
let _c = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[3],
capabilities: lsp::ServerCapabilities {
hover_provider: None,
..lsp::ServerCapabilities::default()
),
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[3],
capabilities: lsp::ServerCapabilities {
hover_provider: None,
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
),
];
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/dir/a.tsx", cx))
@ -4749,7 +4753,7 @@ async fn test_multiple_language_server_hovers(cx: &mut gpui::TestAppContext) {
let mut servers_with_hover_requests = HashMap::default();
for i in 0..language_server_names.len() {
let new_server = fake_tsx_language_servers.next().await.unwrap_or_else(|| {
let new_server = language_servers[i].next().await.unwrap_or_else(|| {
panic!(
"Failed to get language server #{i} with name {}",
&language_server_names[i]
@ -4840,7 +4844,7 @@ async fn test_hovers_with_empty_parts(cx: &mut gpui::TestAppContext) {
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
language_registry.add(typescript_lang());
let mut fake_language_servers = language_registry.register_fake_lsp_adapter(
let mut fake_language_servers = language_registry.register_fake_lsp(
"TypeScript",
FakeLspAdapter {
capabilities: lsp::ServerCapabilities {
@ -4916,50 +4920,53 @@ async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) {
"ESLintServer",
"NoActionsCapabilitiesServer",
];
let mut fake_tsx_language_servers = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[0],
capabilities: lsp::ServerCapabilities {
code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
let mut language_server_rxs = [
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[0],
capabilities: lsp::ServerCapabilities {
code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
let _a = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[1],
capabilities: lsp::ServerCapabilities {
code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
),
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[1],
capabilities: lsp::ServerCapabilities {
code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
let _b = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[2],
capabilities: lsp::ServerCapabilities {
code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
),
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[2],
capabilities: lsp::ServerCapabilities {
code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
let _c = language_registry.register_fake_lsp_adapter(
"tsx",
FakeLspAdapter {
name: language_server_names[3],
capabilities: lsp::ServerCapabilities {
code_action_provider: None,
..lsp::ServerCapabilities::default()
),
language_registry.register_fake_lsp(
"tsx",
FakeLspAdapter {
name: language_server_names[3],
capabilities: lsp::ServerCapabilities {
code_action_provider: None,
..lsp::ServerCapabilities::default()
},
..FakeLspAdapter::default()
},
..FakeLspAdapter::default()
},
);
),
];
let buffer = project
.update(cx, |p, cx| p.open_local_buffer("/dir/a.tsx", cx))
@ -4969,13 +4976,14 @@ async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) {
let mut servers_with_actions_requests = HashMap::default();
for i in 0..language_server_names.len() {
let new_server = fake_tsx_language_servers.next().await.unwrap_or_else(|| {
let new_server = language_server_rxs[i].next().await.unwrap_or_else(|| {
panic!(
"Failed to get language server #{i} with name {}",
&language_server_names[i]
)
});
let new_server_name = new_server.server.name();
assert!(
!servers_with_actions_requests.contains_key(new_server_name),
"Unexpected: initialized server with the same name twice. Name: `{new_server_name}`"
@ -5023,6 +5031,8 @@ async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) {
let code_actions_task = project.update(cx, |project, cx| {
project.code_actions(&buffer, 0..buffer.read(cx).len(), cx)
});
// cx.run_until_parked();
let _: Vec<()> = futures::future::join_all(servers_with_actions_requests.into_values().map(
|mut code_actions_request| async move {
code_actions_request