Stop sending redundant LSP proto requests (#35581)
Before, each time any LSP feature was used on client remote, it always produced a `proto::` request that always had been sent to the host, from where returned as an empty response. Instead, propagate more language server-related data to the client, `lsp::ServerCapability`, so Zed client can omit certain requests if those are not supported. On top of that, rework the approach Zed uses to query for the data refreshes: before, editors tried to fetch the data when the server start was reported (locally and remotely). Now, a later event is selected: on each `textDocument/didOpen` for the buffer contained in this editor, we will query for new LSP data, reusing the cache if needed. Before, servers could reject unregistered files' LSP queries, or process them slowly when starting up. Now, such refreshes are happening later and should be cached. This requires a collab DB change, to restore server data on rejoin. Release Notes: - Fixed excessive LSP requests sent during remote sessions
This commit is contained in:
parent
5b40b3618f
commit
22473fc611
19 changed files with 793 additions and 351 deletions
|
@ -173,6 +173,7 @@ CREATE TABLE "language_servers" (
|
|||
"id" INTEGER NOT NULL,
|
||||
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
|
||||
"name" VARCHAR NOT NULL,
|
||||
"capabilities" TEXT NOT NULL,
|
||||
PRIMARY KEY (project_id, id)
|
||||
);
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE language_servers
|
||||
ADD COLUMN capabilities TEXT NOT NULL DEFAULT '{}';
|
||||
|
||||
ALTER TABLE language_servers
|
||||
ALTER COLUMN capabilities DROP DEFAULT;
|
|
@ -529,11 +529,17 @@ pub struct RejoinedProject {
|
|||
pub worktrees: Vec<RejoinedWorktree>,
|
||||
pub updated_repositories: Vec<proto::UpdateRepository>,
|
||||
pub removed_repositories: Vec<u64>,
|
||||
pub language_servers: Vec<proto::LanguageServer>,
|
||||
pub language_servers: Vec<LanguageServer>,
|
||||
}
|
||||
|
||||
impl RejoinedProject {
|
||||
pub fn to_proto(&self) -> proto::RejoinedProject {
|
||||
let (language_servers, language_server_capabilities) = self
|
||||
.language_servers
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|server| (server.server, server.capabilities))
|
||||
.unzip();
|
||||
proto::RejoinedProject {
|
||||
id: self.id.to_proto(),
|
||||
worktrees: self
|
||||
|
@ -551,7 +557,8 @@ impl RejoinedProject {
|
|||
.iter()
|
||||
.map(|collaborator| collaborator.to_proto())
|
||||
.collect(),
|
||||
language_servers: self.language_servers.clone(),
|
||||
language_servers,
|
||||
language_server_capabilities,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -598,7 +605,7 @@ pub struct Project {
|
|||
pub collaborators: Vec<ProjectCollaborator>,
|
||||
pub worktrees: BTreeMap<u64, Worktree>,
|
||||
pub repositories: Vec<proto::UpdateRepository>,
|
||||
pub language_servers: Vec<proto::LanguageServer>,
|
||||
pub language_servers: Vec<LanguageServer>,
|
||||
}
|
||||
|
||||
pub struct ProjectCollaborator {
|
||||
|
@ -623,6 +630,12 @@ impl ProjectCollaborator {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LanguageServer {
|
||||
pub server: proto::LanguageServer,
|
||||
pub capabilities: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LeftProject {
|
||||
pub id: ProjectId,
|
||||
|
|
|
@ -786,6 +786,32 @@ impl Database {
|
|||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// Update language server capabilities for a given id.
|
||||
pub async fn update_server_capabilities(
|
||||
&self,
|
||||
project_id: ProjectId,
|
||||
server_id: u64,
|
||||
new_capabilities: String,
|
||||
) -> Result<()> {
|
||||
self.transaction(|tx| {
|
||||
let new_capabilities = new_capabilities.clone();
|
||||
async move {
|
||||
Ok(
|
||||
language_server::Entity::update(language_server::ActiveModel {
|
||||
project_id: ActiveValue::unchanged(project_id),
|
||||
id: ActiveValue::unchanged(server_id as i64),
|
||||
capabilities: ActiveValue::set(new_capabilities),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&*tx)
|
||||
.await?,
|
||||
)
|
||||
}
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn operation_to_storage(
|
||||
|
|
|
@ -692,6 +692,7 @@ impl Database {
|
|||
project_id: ActiveValue::set(project_id),
|
||||
id: ActiveValue::set(server.id as i64),
|
||||
name: ActiveValue::set(server.name.clone()),
|
||||
capabilities: ActiveValue::set(update.capabilities.clone()),
|
||||
})
|
||||
.on_conflict(
|
||||
OnConflict::columns([
|
||||
|
@ -1054,10 +1055,13 @@ impl Database {
|
|||
repositories,
|
||||
language_servers: language_servers
|
||||
.into_iter()
|
||||
.map(|language_server| proto::LanguageServer {
|
||||
id: language_server.id as u64,
|
||||
name: language_server.name,
|
||||
worktree_id: None,
|
||||
.map(|language_server| LanguageServer {
|
||||
server: proto::LanguageServer {
|
||||
id: language_server.id as u64,
|
||||
name: language_server.name,
|
||||
worktree_id: None,
|
||||
},
|
||||
capabilities: language_server.capabilities,
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
|
|
@ -804,10 +804,13 @@ impl Database {
|
|||
.all(tx)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|language_server| proto::LanguageServer {
|
||||
id: language_server.id as u64,
|
||||
name: language_server.name,
|
||||
worktree_id: None,
|
||||
.map(|language_server| LanguageServer {
|
||||
server: proto::LanguageServer {
|
||||
id: language_server.id as u64,
|
||||
name: language_server.name,
|
||||
worktree_id: None,
|
||||
},
|
||||
capabilities: language_server.capabilities,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ pub struct Model {
|
|||
#[sea_orm(primary_key)]
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub capabilities: String,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
|
|
|
@ -1990,12 +1990,19 @@ async fn join_project(
|
|||
}
|
||||
|
||||
// First, we send the metadata associated with each worktree.
|
||||
let (language_servers, language_server_capabilities) = project
|
||||
.language_servers
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|server| (server.server, server.capabilities))
|
||||
.unzip();
|
||||
response.send(proto::JoinProjectResponse {
|
||||
project_id: project.id.0 as u64,
|
||||
worktrees: worktrees.clone(),
|
||||
replica_id: replica_id.0 as u32,
|
||||
collaborators: collaborators.clone(),
|
||||
language_servers: project.language_servers.clone(),
|
||||
language_servers,
|
||||
language_server_capabilities,
|
||||
role: project.role.into(),
|
||||
})?;
|
||||
|
||||
|
@ -2054,8 +2061,8 @@ async fn join_project(
|
|||
session.connection_id,
|
||||
proto::UpdateLanguageServer {
|
||||
project_id: project_id.to_proto(),
|
||||
server_name: Some(language_server.name.clone()),
|
||||
language_server_id: language_server.id,
|
||||
server_name: Some(language_server.server.name.clone()),
|
||||
language_server_id: language_server.server.id,
|
||||
variant: Some(
|
||||
proto::update_language_server::Variant::DiskBasedDiagnosticsUpdated(
|
||||
proto::LspDiskBasedDiagnosticsUpdated {},
|
||||
|
@ -2267,9 +2274,17 @@ async fn update_language_server(
|
|||
session: Session,
|
||||
) -> Result<()> {
|
||||
let project_id = ProjectId::from_proto(request.project_id);
|
||||
let project_connection_ids = session
|
||||
.db()
|
||||
.await
|
||||
let db = session.db().await;
|
||||
|
||||
if let Some(proto::update_language_server::Variant::MetadataUpdated(update)) = &request.variant
|
||||
{
|
||||
if let Some(capabilities) = update.capabilities.clone() {
|
||||
db.update_server_capabilities(project_id, request.language_server_id, capabilities)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
let project_connection_ids = db
|
||||
.project_connection_ids(project_id, session.connection_id, true)
|
||||
.await?;
|
||||
broadcast(
|
||||
|
|
|
@ -296,19 +296,28 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
|
|||
.await;
|
||||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![".".to_string()]),
|
||||
resolve_provider: Some(true),
|
||||
..lsp::CompletionOptions::default()
|
||||
}),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![".".to_string()]),
|
||||
resolve_provider: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -566,11 +575,14 @@ async fn test_collaborating_with_code_actions(
|
|||
|
||||
cx_b.update(editor::init);
|
||||
|
||||
// Set up a fake language server.
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp("Rust", FakeLspAdapter::default());
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b
|
||||
.language_registry()
|
||||
.register_fake_lsp("Rust", FakeLspAdapter::default());
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
|
@ -775,19 +787,27 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
|
|||
|
||||
cx_b.update(editor::init);
|
||||
|
||||
// Set up a fake language server.
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
|
||||
prepare_provider: Some(true),
|
||||
work_done_progress_options: Default::default(),
|
||||
})),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
|
||||
prepare_provider: Some(true),
|
||||
work_done_progress_options: Default::default(),
|
||||
})),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -818,6 +838,8 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
|
|||
.downcast::<Editor>()
|
||||
.unwrap();
|
||||
let fake_language_server = fake_language_servers.next().await.unwrap();
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
// Move cursor to a location that can be renamed.
|
||||
let prepare_rename = editor_b.update_in(cx_b, |editor, window, cx| {
|
||||
|
@ -1055,7 +1077,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
|
|||
|
||||
project_a.read_with(cx_a, |project, cx| {
|
||||
let status = project.language_server_statuses(cx).next().unwrap().1;
|
||||
assert_eq!(status.name, "the-language-server");
|
||||
assert_eq!(status.name.0, "the-language-server");
|
||||
assert_eq!(status.pending_work.len(), 1);
|
||||
assert_eq!(
|
||||
status.pending_work["the-token"].message.as_ref().unwrap(),
|
||||
|
@ -1072,7 +1094,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
|
|||
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
let status = project.language_server_statuses(cx).next().unwrap().1;
|
||||
assert_eq!(status.name, "the-language-server");
|
||||
assert_eq!(status.name.0, "the-language-server");
|
||||
});
|
||||
|
||||
executor.advance_clock(SERVER_PROGRESS_THROTTLE_TIMEOUT);
|
||||
|
@ -1089,7 +1111,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
|
|||
|
||||
project_a.read_with(cx_a, |project, cx| {
|
||||
let status = project.language_server_statuses(cx).next().unwrap().1;
|
||||
assert_eq!(status.name, "the-language-server");
|
||||
assert_eq!(status.name.0, "the-language-server");
|
||||
assert_eq!(status.pending_work.len(), 1);
|
||||
assert_eq!(
|
||||
status.pending_work["the-token"].message.as_ref().unwrap(),
|
||||
|
@ -1099,7 +1121,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
|
|||
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
let status = project.language_server_statuses(cx).next().unwrap().1;
|
||||
assert_eq!(status.name, "the-language-server");
|
||||
assert_eq!(status.name.0, "the-language-server");
|
||||
assert_eq!(status.pending_work.len(), 1);
|
||||
assert_eq!(
|
||||
status.pending_work["the-token"].message.as_ref().unwrap(),
|
||||
|
@ -1422,18 +1444,27 @@ async fn test_on_input_format_from_guest_to_host(
|
|||
.await;
|
||||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
|
||||
first_trigger_character: ":".to_string(),
|
||||
more_trigger_character: Some(vec![">".to_string()]),
|
||||
}),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
|
||||
first_trigger_character: ":".to_string(),
|
||||
more_trigger_character: Some(vec![">".to_string()]),
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -1588,16 +1619,24 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
|||
});
|
||||
});
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
inlay_hint_provider: Some(lsp::OneOf::Left(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
client_b.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
inlay_hint_provider: Some(lsp::OneOf::Left(true)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -1830,16 +1869,24 @@ async fn test_inlay_hint_refresh_is_forwarded(
|
|||
});
|
||||
});
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
inlay_hint_provider: Some(lsp::OneOf::Left(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
client_b.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
inlay_hint_provider: Some(lsp::OneOf::Left(true)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -2004,15 +2051,23 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
|
|||
});
|
||||
});
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
color_provider: Some(lsp::ColorProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
client_b.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
color_provider: Some(lsp::ColorProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
},
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
@ -2063,6 +2118,8 @@ async fn test_lsp_document_color(cx_a: &mut TestAppContext, cx_b: &mut TestAppCo
|
|||
.unwrap();
|
||||
|
||||
let fake_language_server = fake_language_servers.next().await.unwrap();
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
let requests_made = Arc::new(AtomicUsize::new(0));
|
||||
let closure_requests_made = Arc::clone(&requests_made);
|
||||
|
@ -2264,24 +2321,32 @@ async fn test_lsp_pull_diagnostics(
|
|||
cx_a.update(editor::init);
|
||||
cx_b.update(editor::init);
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
diagnostic_provider: Some(lsp::DiagnosticServerCapabilities::Options(
|
||||
lsp::DiagnosticOptions {
|
||||
identifier: Some("test-pulls".to_string()),
|
||||
inter_file_dependencies: true,
|
||||
workspace_diagnostics: true,
|
||||
work_done_progress_options: lsp::WorkDoneProgressOptions {
|
||||
work_done_progress: None,
|
||||
},
|
||||
},
|
||||
)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
client_b.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
diagnostic_provider: Some(lsp::DiagnosticServerCapabilities::Options(
|
||||
lsp::DiagnosticOptions {
|
||||
identifier: Some("test-pulls".to_string()),
|
||||
inter_file_dependencies: true,
|
||||
workspace_diagnostics: true,
|
||||
work_done_progress_options: lsp::WorkDoneProgressOptions {
|
||||
work_done_progress: None,
|
||||
},
|
||||
},
|
||||
)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
},
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
@ -2334,6 +2399,8 @@ async fn test_lsp_pull_diagnostics(
|
|||
.unwrap();
|
||||
|
||||
let fake_language_server = fake_language_servers.next().await.unwrap();
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
let expected_push_diagnostic_main_message = "pushed main diagnostic";
|
||||
let expected_push_diagnostic_lib_message = "pushed lib diagnostic";
|
||||
let expected_pull_diagnostic_main_message = "pulled main diagnostic";
|
||||
|
@ -2689,6 +2756,7 @@ async fn test_lsp_pull_diagnostics(
|
|||
.unwrap()
|
||||
.downcast::<Editor>()
|
||||
.unwrap();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
pull_diagnostics_handle.next().await.unwrap();
|
||||
assert_eq!(
|
||||
|
|
|
@ -4778,10 +4778,27 @@ async fn test_definition(
|
|||
.await;
|
||||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
definition_provider: Some(OneOf::Left(true)),
|
||||
type_definition_provider: Some(lsp::TypeDefinitionProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
|
@ -4827,13 +4844,19 @@ async fn test_definition(
|
|||
)))
|
||||
},
|
||||
);
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
let definitions_1 = project_b
|
||||
.update(cx_b, |p, cx| p.definitions(&buffer_b, 23, cx))
|
||||
.await
|
||||
.unwrap();
|
||||
cx_b.read(|cx| {
|
||||
assert_eq!(definitions_1.len(), 1);
|
||||
assert_eq!(
|
||||
definitions_1.len(),
|
||||
1,
|
||||
"Unexpected definitions: {definitions_1:?}"
|
||||
);
|
||||
assert_eq!(project_b.read(cx).worktrees(cx).count(), 2);
|
||||
let target_buffer = definitions_1[0].target.buffer.read(cx);
|
||||
assert_eq!(
|
||||
|
@ -4901,7 +4924,11 @@ async fn test_definition(
|
|||
.await
|
||||
.unwrap();
|
||||
cx_b.read(|cx| {
|
||||
assert_eq!(type_definitions.len(), 1);
|
||||
assert_eq!(
|
||||
type_definitions.len(),
|
||||
1,
|
||||
"Unexpected type definitions: {type_definitions:?}"
|
||||
);
|
||||
let target_buffer = type_definitions[0].target.buffer.read(cx);
|
||||
assert_eq!(target_buffer.text(), "type T2 = usize;");
|
||||
assert_eq!(
|
||||
|
@ -4925,16 +4952,26 @@ async fn test_references(
|
|||
.await;
|
||||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
references_provider: Some(lsp::OneOf::Left(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "my-fake-lsp-adapter",
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
references_provider: Some(lsp::OneOf::Left(true)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "my-fake-lsp-adapter",
|
||||
capabilities: capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -4989,6 +5026,8 @@ async fn test_references(
|
|||
}
|
||||
}
|
||||
});
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
let references = project_b.update(cx_b, |p, cx| p.references(&buffer_b, 7, cx));
|
||||
|
||||
|
@ -4996,7 +5035,7 @@ async fn test_references(
|
|||
executor.run_until_parked();
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
let status = project.language_server_statuses(cx).next().unwrap().1;
|
||||
assert_eq!(status.name, "my-fake-lsp-adapter");
|
||||
assert_eq!(status.name.0, "my-fake-lsp-adapter");
|
||||
assert_eq!(
|
||||
status.pending_work.values().next().unwrap().message,
|
||||
Some("Finding references...".into())
|
||||
|
@ -5054,7 +5093,7 @@ async fn test_references(
|
|||
executor.run_until_parked();
|
||||
project_b.read_with(cx_b, |project, cx| {
|
||||
let status = project.language_server_statuses(cx).next().unwrap().1;
|
||||
assert_eq!(status.name, "my-fake-lsp-adapter");
|
||||
assert_eq!(status.name.0, "my-fake-lsp-adapter");
|
||||
assert_eq!(
|
||||
status.pending_work.values().next().unwrap().message,
|
||||
Some("Finding references...".into())
|
||||
|
@ -5204,10 +5243,26 @@ async fn test_document_highlights(
|
|||
)
|
||||
.await;
|
||||
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
document_highlight_provider: Some(lsp::OneOf::Left(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
let (project_a, worktree_id) = client_a.build_local_project(path!("/root-1"), cx_a).await;
|
||||
let project_id = active_call_a
|
||||
|
@ -5256,6 +5311,8 @@ async fn test_document_highlights(
|
|||
]))
|
||||
},
|
||||
);
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
let highlights = project_b
|
||||
.update(cx_b, |p, cx| p.document_highlights(&buffer_b, 34, cx))
|
||||
|
@ -5306,30 +5363,49 @@ async fn test_lsp_hover(
|
|||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let language_server_names = ["rust-analyzer", "CrabLang-ls"];
|
||||
let capabilities_1 = lsp::ServerCapabilities {
|
||||
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
let capabilities_2 = lsp::ServerCapabilities {
|
||||
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
let mut language_servers = [
|
||||
client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "rust-analyzer",
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
},
|
||||
name: language_server_names[0],
|
||||
capabilities: capabilities_1.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
),
|
||||
client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "CrabLang-ls",
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
},
|
||||
name: language_server_names[1],
|
||||
capabilities: capabilities_2.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
),
|
||||
];
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: language_server_names[0],
|
||||
capabilities: capabilities_1,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: language_server_names[1],
|
||||
capabilities: capabilities_2,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
let (project_a, worktree_id) = client_a.build_local_project(path!("/root-1"), cx_a).await;
|
||||
let project_id = active_call_a
|
||||
|
@ -5423,6 +5499,8 @@ async fn test_lsp_hover(
|
|||
unexpected => panic!("Unexpected server name: {unexpected}"),
|
||||
}
|
||||
}
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
|
||||
// Request hover information as the guest.
|
||||
let mut hovers = project_b
|
||||
|
@ -5605,10 +5683,26 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
|||
.await;
|
||||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
let capabilities = lsp::ServerCapabilities {
|
||||
definition_provider: Some(OneOf::Left(true)),
|
||||
..lsp::ServerCapabilities::default()
|
||||
};
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: capabilities.clone(),
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
client_b.language_registry().add(rust_lang());
|
||||
client_b.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
|
@ -5649,6 +5743,8 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
|||
let definitions;
|
||||
let buffer_b2;
|
||||
if rng.r#gen() {
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
definitions = project_b.update(cx_b, |p, cx| p.definitions(&buffer_b1, 23, cx));
|
||||
(buffer_b2, _) = project_b
|
||||
.update(cx_b, |p, cx| {
|
||||
|
@ -5663,11 +5759,17 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
|||
})
|
||||
.await
|
||||
.unwrap();
|
||||
cx_a.run_until_parked();
|
||||
cx_b.run_until_parked();
|
||||
definitions = project_b.update(cx_b, |p, cx| p.definitions(&buffer_b1, 23, cx));
|
||||
}
|
||||
|
||||
let definitions = definitions.await.unwrap();
|
||||
assert_eq!(definitions.len(), 1);
|
||||
assert_eq!(
|
||||
definitions.len(),
|
||||
1,
|
||||
"Unexpected definitions: {definitions:?}"
|
||||
);
|
||||
assert_eq!(definitions[0].target.buffer, buffer_b2);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue