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:
parent
01bb10f518
commit
e66ea9e5d4
34 changed files with 505 additions and 329 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -9058,6 +9058,7 @@ dependencies = [
|
|||
"http_client",
|
||||
"language",
|
||||
"log",
|
||||
"lsp",
|
||||
"node_runtime",
|
||||
"project",
|
||||
"remote",
|
||||
|
|
|
@ -997,14 +997,14 @@ impl Context {
|
|||
fn handle_buffer_event(
|
||||
&mut self,
|
||||
_: Model<Buffer>,
|
||||
event: &language::Event,
|
||||
event: &language::BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
language::Event::Operation(operation) => cx.emit(ContextEvent::Operation(
|
||||
language::BufferEvent::Operation(operation) => cx.emit(ContextEvent::Operation(
|
||||
ContextOperation::BufferOperation(operation.clone()),
|
||||
)),
|
||||
language::Event::Edited => {
|
||||
language::BufferEvent::Edited => {
|
||||
self.count_remaining_tokens(cx);
|
||||
self.reparse(cx);
|
||||
// Use `inclusive = true` to invalidate a step when an edit occurs
|
||||
|
|
|
@ -1200,6 +1200,7 @@ impl Room {
|
|||
room_id: self.id(),
|
||||
worktrees: vec![],
|
||||
dev_server_project_id: Some(dev_server_project_id.0),
|
||||
is_ssh_project: false,
|
||||
})
|
||||
} else {
|
||||
if let Some(project_id) = project.read(cx).remote_id() {
|
||||
|
@ -1210,6 +1211,7 @@ impl Room {
|
|||
room_id: self.id(),
|
||||
worktrees: project.read(cx).worktree_metadata_protos(cx),
|
||||
dev_server_project_id: None,
|
||||
is_ssh_project: project.read(cx).is_via_ssh(),
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
@ -171,11 +171,11 @@ impl ChannelBuffer {
|
|||
fn on_buffer_update(
|
||||
&mut self,
|
||||
_: Model<language::Buffer>,
|
||||
event: &language::Event,
|
||||
event: &language::BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
language::Event::Operation(operation) => {
|
||||
language::BufferEvent::Operation(operation) => {
|
||||
if *ZED_ALWAYS_ACTIVE {
|
||||
if let language::Operation::UpdateSelections { selections, .. } = operation {
|
||||
if selections.is_empty() {
|
||||
|
@ -191,7 +191,7 @@ impl ChannelBuffer {
|
|||
})
|
||||
.log_err();
|
||||
}
|
||||
language::Event::Edited => {
|
||||
language::BufferEvent::Edited => {
|
||||
cx.emit(ChannelBufferEvent::BufferEdited);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -30,6 +30,7 @@ impl Database {
|
|||
room_id: RoomId,
|
||||
connection: ConnectionId,
|
||||
worktrees: &[proto::WorktreeMetadata],
|
||||
is_ssh_project: bool,
|
||||
dev_server_project_id: Option<DevServerProjectId>,
|
||||
) -> Result<TransactionGuard<(ProjectId, proto::Room)>> {
|
||||
self.room_transaction(room_id, |tx| async move {
|
||||
|
@ -121,12 +122,14 @@ impl Database {
|
|||
.await?;
|
||||
}
|
||||
|
||||
let replica_id = if is_ssh_project { 1 } else { 0 };
|
||||
|
||||
project_collaborator::ActiveModel {
|
||||
project_id: ActiveValue::set(project.id),
|
||||
connection_id: ActiveValue::set(connection.id as i32),
|
||||
connection_server_id: ActiveValue::set(ServerId(connection.owner_id as i32)),
|
||||
user_id: ActiveValue::set(participant.user_id),
|
||||
replica_id: ActiveValue::set(ReplicaId(0)),
|
||||
replica_id: ActiveValue::set(ReplicaId(replica_id)),
|
||||
is_host: ActiveValue::set(true),
|
||||
..Default::default()
|
||||
}
|
||||
|
|
|
@ -540,18 +540,18 @@ async fn test_project_count(db: &Arc<Database>) {
|
|||
.unwrap();
|
||||
assert_eq!(db.project_count_excluding_admins().await.unwrap(), 0);
|
||||
|
||||
db.share_project(room_id, ConnectionId { owner_id, id: 1 }, &[], None)
|
||||
db.share_project(room_id, ConnectionId { owner_id, id: 1 }, &[], false, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(db.project_count_excluding_admins().await.unwrap(), 1);
|
||||
|
||||
db.share_project(room_id, ConnectionId { owner_id, id: 1 }, &[], None)
|
||||
db.share_project(room_id, ConnectionId { owner_id, id: 1 }, &[], false, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(db.project_count_excluding_admins().await.unwrap(), 2);
|
||||
|
||||
// Projects shared by admins aren't counted.
|
||||
db.share_project(room_id, ConnectionId { owner_id, id: 0 }, &[], None)
|
||||
db.share_project(room_id, ConnectionId { owner_id, id: 0 }, &[], false, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(db.project_count_excluding_admins().await.unwrap(), 2);
|
||||
|
|
|
@ -1996,6 +1996,7 @@ async fn share_project(
|
|||
RoomId::from_proto(request.room_id),
|
||||
session.connection_id,
|
||||
&request.worktrees,
|
||||
request.is_ssh_project,
|
||||
request
|
||||
.dev_server_project_id
|
||||
.map(DevServerProjectId::from_proto),
|
||||
|
|
|
@ -284,7 +284,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
|
|||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -552,7 +552,7 @@ async fn test_collaborating_with_code_actions(
|
|||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp_adapter("Rust", FakeLspAdapter::default());
|
||||
.register_fake_lsp("Rust", FakeLspAdapter::default());
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
|
@ -757,7 +757,7 @@ async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut T
|
|||
|
||||
// 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_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -982,7 +982,7 @@ async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut Tes
|
|||
cx_b.update(editor::init);
|
||||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "the-language-server",
|
||||
|
@ -1268,7 +1268,7 @@ async fn test_on_input_format_from_host_to_guest(
|
|||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -1388,7 +1388,7 @@ async fn test_on_input_format_from_guest_to_host(
|
|||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -1545,7 +1545,7 @@ async fn test_mutual_editor_inlay_hint_cache_update(
|
|||
|
||||
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_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -1807,7 +1807,7 @@ async fn test_inlay_hint_refresh_is_forwarded(
|
|||
|
||||
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_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
|
|
@ -3859,7 +3859,7 @@ async fn test_collaborating_with_diagnostics(
|
|||
)));
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp_adapter("Rust", Default::default());
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
|
||||
// Share a project as client A
|
||||
client_a
|
||||
|
@ -4126,7 +4126,7 @@ async fn test_collaborating_with_lsp_progress_updates_and_diagnostics_ordering(
|
|||
.await;
|
||||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
disk_based_diagnostics_progress_token: Some("the-disk-based-token".into()),
|
||||
|
@ -4349,7 +4349,7 @@ async fn test_formatting_buffer(
|
|||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp_adapter("Rust", FakeLspAdapter::default());
|
||||
.register_fake_lsp("Rust", FakeLspAdapter::default());
|
||||
|
||||
// Here we insert a fake tree with a directory that exists on disk. This is needed
|
||||
// because later we'll invoke a command, which requires passing a working directory
|
||||
|
@ -4460,7 +4460,7 @@ async fn test_prettier_formatting_buffer(
|
|||
},
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"TypeScript",
|
||||
FakeLspAdapter {
|
||||
prettier_plugins: vec![test_plugin],
|
||||
|
@ -4576,7 +4576,7 @@ async fn test_definition(
|
|||
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp_adapter("Rust", Default::default());
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
client_a.language_registry().add(rust_lang());
|
||||
|
||||
client_a
|
||||
|
@ -4712,7 +4712,7 @@ async fn test_references(
|
|||
let active_call_a = cx_a.read(ActiveCall::global);
|
||||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "my-fake-lsp-adapter",
|
||||
|
@ -4983,7 +4983,7 @@ async fn test_document_highlights(
|
|||
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp_adapter("Rust", Default::default());
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
client_a.language_registry().add(rust_lang());
|
||||
|
||||
let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
|
||||
|
@ -5079,28 +5079,30 @@ async fn test_lsp_hover(
|
|||
|
||||
client_a.language_registry().add(rust_lang());
|
||||
let language_server_names = ["rust-analyzer", "CrabLang-ls"];
|
||||
let mut fake_language_servers = client_a.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "rust-analyzer",
|
||||
capabilities: 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()
|
||||
},
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
let _other_server = client_a.language_registry().register_fake_lsp_adapter(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "CrabLang-ls",
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
|
||||
..lsp::ServerCapabilities::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()
|
||||
},
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
..FakeLspAdapter::default()
|
||||
},
|
||||
);
|
||||
),
|
||||
];
|
||||
|
||||
let (project_a, worktree_id) = client_a.build_local_project("/root-1", cx_a).await;
|
||||
let project_id = active_call_a
|
||||
|
@ -5115,7 +5117,7 @@ async fn test_lsp_hover(
|
|||
|
||||
let mut servers_with_hover_requests = HashMap::default();
|
||||
for i in 0..language_server_names.len() {
|
||||
let new_server = fake_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]
|
||||
|
@ -5260,7 +5262,7 @@ async fn test_project_symbols(
|
|||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp_adapter("Rust", Default::default());
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
|
@ -5362,7 +5364,7 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
|||
client_a.language_registry().add(rust_lang());
|
||||
let mut fake_language_servers = client_a
|
||||
.language_registry()
|
||||
.register_fake_lsp_adapter("Rust", Default::default());
|
||||
.register_fake_lsp("Rust", Default::default());
|
||||
|
||||
client_a
|
||||
.fs()
|
||||
|
|
|
@ -1047,7 +1047,7 @@ impl RandomizedTest for ProjectCollaborationTest {
|
|||
},
|
||||
None,
|
||||
)));
|
||||
client.language_registry().register_fake_lsp_adapter(
|
||||
client.language_registry().register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: "the-fake-language-server",
|
||||
|
|
|
@ -228,10 +228,10 @@ impl MessageEditor {
|
|||
fn on_buffer_event(
|
||||
&mut self,
|
||||
buffer: Model<Buffer>,
|
||||
event: &language::Event,
|
||||
event: &language::BufferEvent,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
if let language::Event::Reparsed | language::Event::Edited = event {
|
||||
if let language::BufferEvent::Reparsed | language::BufferEvent::Edited = event {
|
||||
let buffer = buffer.read(cx).snapshot();
|
||||
self.mentions_task = Some(cx.spawn(|this, cx| async move {
|
||||
cx.background_executor()
|
||||
|
|
|
@ -691,17 +691,17 @@ impl Copilot {
|
|||
fn handle_buffer_event(
|
||||
&mut self,
|
||||
buffer: Model<Buffer>,
|
||||
event: &language::Event,
|
||||
event: &language::BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Result<()> {
|
||||
if let Ok(server) = self.server.as_running() {
|
||||
if let Some(registered_buffer) = server.registered_buffers.get_mut(&buffer.entity_id())
|
||||
{
|
||||
match event {
|
||||
language::Event::Edited => {
|
||||
language::BufferEvent::Edited => {
|
||||
drop(registered_buffer.report_changes(&buffer, cx));
|
||||
}
|
||||
language::Event::Saved => {
|
||||
language::BufferEvent::Saved => {
|
||||
server
|
||||
.lsp
|
||||
.notify::<lsp::notification::DidSaveTextDocument>(
|
||||
|
@ -713,7 +713,8 @@ impl Copilot {
|
|||
},
|
||||
)?;
|
||||
}
|
||||
language::Event::FileHandleChanged | language::Event::LanguageChanged => {
|
||||
language::BufferEvent::FileHandleChanged
|
||||
| language::BufferEvent::LanguageChanged => {
|
||||
let new_language_id = id_for_language(buffer.read(cx).language());
|
||||
let new_uri = uri_for_buffer(&buffer, cx);
|
||||
if new_uri != registered_buffer.uri
|
||||
|
|
|
@ -6205,7 +6205,7 @@ async fn test_document_format_during_save(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 {
|
||||
|
@ -6361,7 +6361,7 @@ async fn test_multibuffer_format_during_save(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 {
|
||||
|
@ -6557,7 +6557,7 @@ async fn test_range_format_during_save(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 {
|
||||
|
@ -6708,7 +6708,7 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
|
|||
..PrettierSettings::default()
|
||||
});
|
||||
});
|
||||
let mut fake_servers = language_registry.register_fake_lsp_adapter(
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -9488,7 +9488,7 @@ async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) {
|
|||
},
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
let mut fake_servers = language_registry.register_fake_lsp_adapter(
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -9601,7 +9601,7 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test
|
|||
},
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
let mut fake_servers = language_registry.register_fake_lsp_adapter(
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
name: language_server_name,
|
||||
|
@ -9945,7 +9945,7 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
|
|||
});
|
||||
|
||||
let test_plugin = "test_plugin";
|
||||
let _ = language_registry.register_fake_lsp_adapter(
|
||||
let _ = language_registry.register_fake_lsp(
|
||||
"TypeScript",
|
||||
FakeLspAdapter {
|
||||
prettier_plugins: vec![test_plugin],
|
||||
|
|
|
@ -121,12 +121,12 @@ impl GitBlame {
|
|||
);
|
||||
|
||||
let buffer_subscriptions = cx.subscribe(&buffer, |this, buffer, event, cx| match event {
|
||||
language::Event::DirtyChanged => {
|
||||
language::BufferEvent::DirtyChanged => {
|
||||
if !buffer.read(cx).is_dirty() {
|
||||
this.generate(cx);
|
||||
}
|
||||
}
|
||||
language::Event::Edited => {
|
||||
language::BufferEvent::Edited => {
|
||||
this.regenerate_on_edit(cx);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -1577,7 +1577,7 @@ pub mod tests {
|
|||
},
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
let fake_servers = language_registry.register_fake_lsp_adapter(
|
||||
let fake_servers = language_registry.register_fake_lsp(
|
||||
name,
|
||||
FakeLspAdapter {
|
||||
name,
|
||||
|
@ -2273,7 +2273,7 @@ pub mod tests {
|
|||
|
||||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
language_registry.add(crate::editor_tests::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 {
|
||||
|
@ -2569,7 +2569,7 @@ pub mod tests {
|
|||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
let language = crate::editor_tests::rust_lang();
|
||||
language_registry.add(language);
|
||||
let mut fake_servers = language_registry.register_fake_lsp_adapter(
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
"Rust",
|
||||
FakeLspAdapter {
|
||||
capabilities: lsp::ServerCapabilities {
|
||||
|
@ -2919,7 +2919,7 @@ pub mod tests {
|
|||
|
||||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
language_registry.add(crate::editor_tests::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 {
|
||||
|
@ -3148,7 +3148,7 @@ pub mod tests {
|
|||
|
||||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
language_registry.add(crate::editor_tests::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 {
|
||||
|
@ -3389,7 +3389,7 @@ pub mod tests {
|
|||
|
||||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
language_registry.add(crate::editor_tests::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 {
|
||||
|
|
|
@ -57,7 +57,7 @@ impl EditorLspTestContext {
|
|||
let project = Project::test(app_state.fs.clone(), [], cx).await;
|
||||
|
||||
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||
let mut fake_servers = language_registry.register_fake_lsp_adapter(
|
||||
let mut fake_servers = language_registry.register_fake_lsp(
|
||||
language.name(),
|
||||
FakeLspAdapter {
|
||||
capabilities,
|
||||
|
|
|
@ -609,7 +609,14 @@ async fn test_extension_store_with_test_extension(cx: &mut TestAppContext) {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut fake_servers = language_registry.fake_language_servers("Gleam".into());
|
||||
let mut fake_servers = language_registry.register_fake_language_server(
|
||||
LanguageServerName("gleam".into()),
|
||||
lsp::ServerCapabilities {
|
||||
completion_provider: Some(Default::default()),
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
);
|
||||
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
|
|
|
@ -302,7 +302,7 @@ pub enum Operation {
|
|||
|
||||
/// An event that occurs in a buffer.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Event {
|
||||
pub enum BufferEvent {
|
||||
/// The buffer was changed in a way that must be
|
||||
/// propagated to its other replicas.
|
||||
Operation(Operation),
|
||||
|
@ -809,7 +809,7 @@ impl Buffer {
|
|||
self.syntax_map.lock().clear();
|
||||
self.language = language;
|
||||
self.reparse(cx);
|
||||
cx.emit(Event::LanguageChanged);
|
||||
cx.emit(BufferEvent::LanguageChanged);
|
||||
}
|
||||
|
||||
/// Assign a language registry to the buffer. This allows the buffer to retrieve
|
||||
|
@ -827,7 +827,7 @@ impl Buffer {
|
|||
/// Assign the buffer a new [Capability].
|
||||
pub fn set_capability(&mut self, capability: Capability, cx: &mut ModelContext<Self>) {
|
||||
self.capability = capability;
|
||||
cx.emit(Event::CapabilityChanged)
|
||||
cx.emit(BufferEvent::CapabilityChanged)
|
||||
}
|
||||
|
||||
/// This method is called to signal that the buffer has been saved.
|
||||
|
@ -842,13 +842,13 @@ impl Buffer {
|
|||
.set((self.saved_version().clone(), false));
|
||||
self.has_conflict = false;
|
||||
self.saved_mtime = mtime;
|
||||
cx.emit(Event::Saved);
|
||||
cx.emit(BufferEvent::Saved);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// This method is called to signal that the buffer has been discarded.
|
||||
pub fn discarded(&mut self, cx: &mut ModelContext<Self>) {
|
||||
cx.emit(Event::Discarded);
|
||||
cx.emit(BufferEvent::Discarded);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
|
@ -911,7 +911,7 @@ impl Buffer {
|
|||
.set((self.saved_version.clone(), false));
|
||||
self.text.set_line_ending(line_ending);
|
||||
self.saved_mtime = mtime;
|
||||
cx.emit(Event::Reloaded);
|
||||
cx.emit(BufferEvent::Reloaded);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
|
@ -929,7 +929,7 @@ impl Buffer {
|
|||
if !old_file.is_deleted() {
|
||||
file_changed = true;
|
||||
if !self.is_dirty() {
|
||||
cx.emit(Event::DirtyChanged);
|
||||
cx.emit(BufferEvent::DirtyChanged);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -949,7 +949,7 @@ impl Buffer {
|
|||
self.file = Some(new_file);
|
||||
if file_changed {
|
||||
self.non_text_state_update_count += 1;
|
||||
cx.emit(Event::FileHandleChanged);
|
||||
cx.emit(BufferEvent::FileHandleChanged);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
@ -974,7 +974,7 @@ impl Buffer {
|
|||
recalc_task.await;
|
||||
buffer
|
||||
.update(&mut cx, |_, cx| {
|
||||
cx.emit(Event::DiffBaseChanged);
|
||||
cx.emit(BufferEvent::DiffBaseChanged);
|
||||
})
|
||||
.ok();
|
||||
})
|
||||
|
@ -1003,7 +1003,7 @@ impl Buffer {
|
|||
this.update(&mut cx, |this, cx| {
|
||||
this.git_diff = buffer_diff;
|
||||
this.non_text_state_update_count += 1;
|
||||
cx.emit(Event::DiffUpdated);
|
||||
cx.emit(BufferEvent::DiffUpdated);
|
||||
})
|
||||
.ok();
|
||||
}))
|
||||
|
@ -1142,7 +1142,7 @@ impl Buffer {
|
|||
self.syntax_map.lock().did_parse(syntax_snapshot);
|
||||
self.request_autoindent(cx);
|
||||
self.parse_status.0.send(ParseStatus::Idle).unwrap();
|
||||
cx.emit(Event::Reparsed);
|
||||
cx.emit(BufferEvent::Reparsed);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
|
@ -1900,9 +1900,9 @@ impl Buffer {
|
|||
|
||||
self.reparse(cx);
|
||||
|
||||
cx.emit(Event::Edited);
|
||||
cx.emit(BufferEvent::Edited);
|
||||
if was_dirty != self.is_dirty() {
|
||||
cx.emit(Event::DirtyChanged);
|
||||
cx.emit(BufferEvent::DirtyChanged);
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
|
@ -2106,12 +2106,12 @@ impl Buffer {
|
|||
self.non_text_state_update_count += 1;
|
||||
self.text.lamport_clock.observe(lamport_timestamp);
|
||||
cx.notify();
|
||||
cx.emit(Event::DiagnosticsUpdated);
|
||||
cx.emit(BufferEvent::DiagnosticsUpdated);
|
||||
}
|
||||
}
|
||||
|
||||
fn send_operation(&mut self, operation: Operation, cx: &mut ModelContext<Self>) {
|
||||
cx.emit(Event::Operation(operation));
|
||||
cx.emit(BufferEvent::Operation(operation));
|
||||
}
|
||||
|
||||
/// Removes the selections for a given peer.
|
||||
|
@ -2300,7 +2300,7 @@ impl Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<Event> for Buffer {}
|
||||
impl EventEmitter<BufferEvent> for Buffer {}
|
||||
|
||||
impl Deref for Buffer {
|
||||
type Target = TextBuffer;
|
||||
|
|
|
@ -275,7 +275,7 @@ fn test_edit_events(cx: &mut gpui::AppContext) {
|
|||
|buffer, cx| {
|
||||
let buffer_1_events = buffer_1_events.clone();
|
||||
cx.subscribe(&buffer1, move |_, _, event, _| match event.clone() {
|
||||
Event::Operation(op) => buffer1_ops.lock().push(op),
|
||||
BufferEvent::Operation(op) => buffer1_ops.lock().push(op),
|
||||
event => buffer_1_events.lock().push(event),
|
||||
})
|
||||
.detach();
|
||||
|
@ -313,15 +313,15 @@ fn test_edit_events(cx: &mut gpui::AppContext) {
|
|||
assert_eq!(
|
||||
mem::take(&mut *buffer_1_events.lock()),
|
||||
vec![
|
||||
Event::Edited,
|
||||
Event::DirtyChanged,
|
||||
Event::Edited,
|
||||
Event::Edited,
|
||||
BufferEvent::Edited,
|
||||
BufferEvent::DirtyChanged,
|
||||
BufferEvent::Edited,
|
||||
BufferEvent::Edited,
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
mem::take(&mut *buffer_2_events.lock()),
|
||||
vec![Event::Edited, Event::DirtyChanged]
|
||||
vec![BufferEvent::Edited, BufferEvent::DirtyChanged]
|
||||
);
|
||||
|
||||
buffer1.update(cx, |buffer, cx| {
|
||||
|
@ -336,11 +336,11 @@ fn test_edit_events(cx: &mut gpui::AppContext) {
|
|||
});
|
||||
assert_eq!(
|
||||
mem::take(&mut *buffer_1_events.lock()),
|
||||
vec![Event::Edited, Event::DirtyChanged,]
|
||||
vec![BufferEvent::Edited, BufferEvent::DirtyChanged,]
|
||||
);
|
||||
assert_eq!(
|
||||
mem::take(&mut *buffer_2_events.lock()),
|
||||
vec![Event::Edited, Event::DirtyChanged]
|
||||
vec![BufferEvent::Edited, BufferEvent::DirtyChanged]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2411,7 +2411,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
|
|||
buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
|
||||
let network = network.clone();
|
||||
cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
|
||||
if let Event::Operation(op) = event {
|
||||
if let BufferEvent::Operation(op) = event {
|
||||
network
|
||||
.lock()
|
||||
.broadcast(buffer.replica_id(), vec![proto::serialize_operation(op)]);
|
||||
|
@ -2539,7 +2539,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
|
|||
new_buffer.set_group_interval(Duration::from_millis(rng.gen_range(0..=200)));
|
||||
let network = network.clone();
|
||||
cx.subscribe(&cx.handle(), move |buffer, _, event, _| {
|
||||
if let Event::Operation(op) = event {
|
||||
if let BufferEvent::Operation(op) = event {
|
||||
network.lock().broadcast(
|
||||
buffer.replica_id(),
|
||||
vec![proto::serialize_operation(op)],
|
||||
|
|
|
@ -270,11 +270,6 @@ impl CachedLspAdapter {
|
|||
.cloned()
|
||||
.unwrap_or_else(|| language_name.lsp_id())
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fn as_fake(&self) -> Option<&FakeLspAdapter> {
|
||||
self.adapter.as_fake()
|
||||
}
|
||||
}
|
||||
|
||||
/// [`LspAdapterDelegate`] allows [`LspAdapter]` implementations to interface with the application
|
||||
|
@ -508,11 +503,6 @@ pub trait LspAdapter: 'static + Send + Sync {
|
|||
fn language_ids(&self) -> HashMap<String, String> {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fn as_fake(&self) -> Option<&FakeLspAdapter> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_fetch_server_binary<L: LspAdapter + 'static + Send + Sync + ?Sized>(
|
||||
|
@ -751,12 +741,13 @@ where
|
|||
pub struct FakeLspAdapter {
|
||||
pub name: &'static str,
|
||||
pub initialization_options: Option<Value>,
|
||||
pub capabilities: lsp::ServerCapabilities,
|
||||
pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
|
||||
pub prettier_plugins: Vec<&'static str>,
|
||||
pub disk_based_diagnostics_progress_token: Option<String>,
|
||||
pub disk_based_diagnostics_sources: Vec<String>,
|
||||
pub prettier_plugins: Vec<&'static str>,
|
||||
pub language_server_binary: LanguageServerBinary,
|
||||
|
||||
pub capabilities: lsp::ServerCapabilities,
|
||||
pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
|
||||
}
|
||||
|
||||
/// Configuration of handling bracket pairs for a given language.
|
||||
|
@ -1717,10 +1708,6 @@ impl LspAdapter for FakeLspAdapter {
|
|||
) -> Result<Option<Value>> {
|
||||
Ok(self.initialization_options.clone())
|
||||
}
|
||||
|
||||
fn as_fake(&self) -> Option<&FakeLspAdapter> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_capture_indices(query: &Query, captures: &mut [(&str, &mut Option<u32>)]) {
|
||||
|
|
|
@ -99,10 +99,15 @@ struct LanguageRegistryState {
|
|||
reload_count: usize,
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fake_server_txs: HashMap<
|
||||
LanguageName,
|
||||
Vec<futures::channel::mpsc::UnboundedSender<lsp::FakeLanguageServer>>,
|
||||
>,
|
||||
fake_server_entries: HashMap<LanguageServerName, FakeLanguageServerEntry>,
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub struct FakeLanguageServerEntry {
|
||||
pub capabilities: lsp::ServerCapabilities,
|
||||
pub initializer: Option<Box<dyn 'static + Send + Sync + Fn(&mut lsp::FakeLanguageServer)>>,
|
||||
pub tx: futures::channel::mpsc::UnboundedSender<lsp::FakeLanguageServer>,
|
||||
pub _server: Option<lsp::FakeLanguageServer>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -220,7 +225,7 @@ impl LanguageRegistry {
|
|||
reload_count: 0,
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
fake_server_txs: Default::default(),
|
||||
fake_server_entries: Default::default(),
|
||||
}),
|
||||
language_server_download_dir: None,
|
||||
lsp_binary_status_tx: Default::default(),
|
||||
|
@ -330,12 +335,35 @@ impl LanguageRegistry {
|
|||
.push(CachedLspAdapter::new(adapter));
|
||||
}
|
||||
|
||||
/// Register a fake language server and adapter
|
||||
/// The returned channel receives a new instance of the language server every time it is started
|
||||
#[cfg(any(feature = "test-support", test))]
|
||||
pub fn register_fake_lsp(
|
||||
&self,
|
||||
language_name: impl Into<LanguageName>,
|
||||
mut adapter: crate::FakeLspAdapter,
|
||||
) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
|
||||
let language_name = language_name.into();
|
||||
let adapter_name = LanguageServerName(adapter.name.into());
|
||||
let capabilities = adapter.capabilities.clone();
|
||||
let initializer = adapter.initializer.take();
|
||||
self.state
|
||||
.write()
|
||||
.lsp_adapters
|
||||
.entry(language_name.clone())
|
||||
.or_default()
|
||||
.push(CachedLspAdapter::new(Arc::new(adapter)));
|
||||
self.register_fake_language_server(adapter_name, capabilities, initializer)
|
||||
}
|
||||
|
||||
/// Register a fake lsp adapter (without the language server)
|
||||
/// The returned channel receives a new instance of the language server every time it is started
|
||||
#[cfg(any(feature = "test-support", test))]
|
||||
pub fn register_fake_lsp_adapter(
|
||||
&self,
|
||||
language_name: impl Into<LanguageName>,
|
||||
adapter: crate::FakeLspAdapter,
|
||||
) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
|
||||
) {
|
||||
let language_name = language_name.into();
|
||||
self.state
|
||||
.write()
|
||||
|
@ -343,21 +371,27 @@ impl LanguageRegistry {
|
|||
.entry(language_name.clone())
|
||||
.or_default()
|
||||
.push(CachedLspAdapter::new(Arc::new(adapter)));
|
||||
self.fake_language_servers(language_name)
|
||||
}
|
||||
|
||||
/// Register a fake language server (without the adapter)
|
||||
/// The returned channel receives a new instance of the language server every time it is started
|
||||
#[cfg(any(feature = "test-support", test))]
|
||||
pub fn fake_language_servers(
|
||||
pub fn register_fake_language_server(
|
||||
&self,
|
||||
language_name: LanguageName,
|
||||
lsp_name: LanguageServerName,
|
||||
capabilities: lsp::ServerCapabilities,
|
||||
initializer: Option<Box<dyn Fn(&mut lsp::FakeLanguageServer) + Send + Sync>>,
|
||||
) -> futures::channel::mpsc::UnboundedReceiver<lsp::FakeLanguageServer> {
|
||||
let (servers_tx, servers_rx) = futures::channel::mpsc::unbounded();
|
||||
self.state
|
||||
.write()
|
||||
.fake_server_txs
|
||||
.entry(language_name)
|
||||
.or_default()
|
||||
.push(servers_tx);
|
||||
self.state.write().fake_server_entries.insert(
|
||||
lsp_name,
|
||||
FakeLanguageServerEntry {
|
||||
tx: servers_tx,
|
||||
capabilities,
|
||||
initializer,
|
||||
_server: None,
|
||||
},
|
||||
);
|
||||
servers_rx
|
||||
}
|
||||
|
||||
|
@ -835,8 +869,8 @@ impl LanguageRegistry {
|
|||
adapter.name.0
|
||||
);
|
||||
|
||||
let download_dir = self
|
||||
.language_server_download_dir
|
||||
let download_dir = &self
|
||||
.language_server_download_dir
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("language server download directory has not been assigned before starting server"))
|
||||
.log_err()?;
|
||||
|
@ -877,52 +911,43 @@ impl LanguageRegistry {
|
|||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
if true {
|
||||
let capabilities = adapter
|
||||
.as_fake()
|
||||
.map(|fake_adapter| fake_adapter.capabilities.clone())
|
||||
.unwrap_or_else(|| lsp::ServerCapabilities {
|
||||
completion_provider: Some(Default::default()),
|
||||
..Default::default()
|
||||
});
|
||||
if let Some(this) = this.upgrade() {
|
||||
if let Some(fake_entry) = this
|
||||
.state
|
||||
.write()
|
||||
.fake_server_entries
|
||||
.get_mut(&adapter.name)
|
||||
{
|
||||
let (server, mut fake_server) = lsp::FakeLanguageServer::new(
|
||||
server_id,
|
||||
binary,
|
||||
adapter.name.0.to_string(),
|
||||
fake_entry.capabilities.clone(),
|
||||
cx.clone(),
|
||||
);
|
||||
fake_entry._server = Some(fake_server.clone());
|
||||
|
||||
let (server, mut fake_server) = lsp::FakeLanguageServer::new(
|
||||
server_id,
|
||||
binary,
|
||||
adapter.name.0.to_string(),
|
||||
capabilities,
|
||||
cx.clone(),
|
||||
);
|
||||
if let Some(initializer) = &fake_entry.initializer {
|
||||
initializer(&mut fake_server);
|
||||
}
|
||||
|
||||
if let Some(fake_adapter) = adapter.as_fake() {
|
||||
if let Some(initializer) = &fake_adapter.initializer {
|
||||
initializer(&mut fake_server);
|
||||
let tx = fake_entry.tx.clone();
|
||||
cx.background_executor()
|
||||
.spawn(async move {
|
||||
if fake_server
|
||||
.try_receive_notification::<lsp::notification::Initialized>(
|
||||
)
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
tx.unbounded_send(fake_server.clone()).ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
return Ok((server, options));
|
||||
}
|
||||
}
|
||||
|
||||
cx.background_executor()
|
||||
.spawn(async move {
|
||||
if fake_server
|
||||
.try_receive_notification::<lsp::notification::Initialized>()
|
||||
.await
|
||||
.is_some()
|
||||
{
|
||||
if let Some(this) = this.upgrade() {
|
||||
if let Some(txs) = this
|
||||
.state
|
||||
.write()
|
||||
.fake_server_txs
|
||||
.get_mut(&_language_name_for_tests)
|
||||
{
|
||||
for tx in txs {
|
||||
tx.unbounded_send(fake_server.clone()).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
return Ok((server, options));
|
||||
}
|
||||
|
||||
drop(this);
|
||||
|
|
|
@ -45,7 +45,7 @@ async fn test_lsp_logs(cx: &mut TestAppContext) {
|
|||
},
|
||||
Some(tree_sitter_rust::language()),
|
||||
)));
|
||||
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",
|
||||
|
|
|
@ -1673,31 +1673,33 @@ impl MultiBuffer {
|
|||
fn on_buffer_event(
|
||||
&mut self,
|
||||
buffer: Model<Buffer>,
|
||||
event: &language::Event,
|
||||
event: &language::BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
cx.emit(match event {
|
||||
language::Event::Edited => Event::Edited {
|
||||
language::BufferEvent::Edited => Event::Edited {
|
||||
singleton_buffer_edited: true,
|
||||
},
|
||||
language::Event::DirtyChanged => Event::DirtyChanged,
|
||||
language::Event::Saved => Event::Saved,
|
||||
language::Event::FileHandleChanged => Event::FileHandleChanged,
|
||||
language::Event::Reloaded => Event::Reloaded,
|
||||
language::Event::DiffBaseChanged => Event::DiffBaseChanged,
|
||||
language::Event::DiffUpdated => Event::DiffUpdated { buffer },
|
||||
language::Event::LanguageChanged => Event::LanguageChanged(buffer.read(cx).remote_id()),
|
||||
language::Event::Reparsed => Event::Reparsed(buffer.read(cx).remote_id()),
|
||||
language::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated,
|
||||
language::Event::Closed => Event::Closed,
|
||||
language::Event::Discarded => Event::Discarded,
|
||||
language::Event::CapabilityChanged => {
|
||||
language::BufferEvent::DirtyChanged => Event::DirtyChanged,
|
||||
language::BufferEvent::Saved => Event::Saved,
|
||||
language::BufferEvent::FileHandleChanged => Event::FileHandleChanged,
|
||||
language::BufferEvent::Reloaded => Event::Reloaded,
|
||||
language::BufferEvent::DiffBaseChanged => Event::DiffBaseChanged,
|
||||
language::BufferEvent::DiffUpdated => Event::DiffUpdated { buffer },
|
||||
language::BufferEvent::LanguageChanged => {
|
||||
Event::LanguageChanged(buffer.read(cx).remote_id())
|
||||
}
|
||||
language::BufferEvent::Reparsed => Event::Reparsed(buffer.read(cx).remote_id()),
|
||||
language::BufferEvent::DiagnosticsUpdated => Event::DiagnosticsUpdated,
|
||||
language::BufferEvent::Closed => Event::Closed,
|
||||
language::BufferEvent::Discarded => Event::Discarded,
|
||||
language::BufferEvent::CapabilityChanged => {
|
||||
self.capability = buffer.read(cx).capability();
|
||||
Event::CapabilityChanged
|
||||
}
|
||||
|
||||
//
|
||||
language::Event::Operation(_) => return,
|
||||
language::BufferEvent::Operation(_) => return,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ impl ExpandedMacro {
|
|||
self.name.is_empty() && self.expansion.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExpandMacro {
|
||||
pub position: PointUtf16,
|
||||
}
|
||||
|
|
|
@ -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| {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -288,7 +288,7 @@ mod tests {
|
|||
None,
|
||||
)));
|
||||
let mut fake_servers =
|
||||
language_registry.register_fake_lsp_adapter("Rust", FakeLspAdapter::default());
|
||||
language_registry.register_fake_lsp("Rust", FakeLspAdapter::default());
|
||||
|
||||
let _buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
|
|
|
@ -497,6 +497,7 @@ message ShareProject {
|
|||
uint64 room_id = 1;
|
||||
repeated WorktreeMetadata worktrees = 2;
|
||||
optional uint64 dev_server_project_id = 3;
|
||||
bool is_ssh_project = 4;
|
||||
}
|
||||
|
||||
message ShareProjectResponse {
|
||||
|
|
|
@ -46,7 +46,9 @@ gpui = { workspace = true, features = ["test-support"] }
|
|||
http_client = { workspace = true, features = ["test-support"] }
|
||||
language = { workspace = true, features = ["test-support"] }
|
||||
node_runtime = { workspace = true, features = ["test-support"] }
|
||||
project = { workspace = true, features = ["test-support"] }
|
||||
remote = { workspace = true, features = ["test-support"] }
|
||||
lsp = { workspace = true, features=["test-support"] }
|
||||
|
||||
serde_json.workspace = true
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use fs::Fs;
|
||||
use gpui::{AppContext, AsyncAppContext, Context, Model, ModelContext};
|
||||
use language::LanguageRegistry;
|
||||
use language::{proto::serialize_operation, Buffer, BufferEvent, LanguageRegistry};
|
||||
use project::{
|
||||
buffer_store::BufferStore, project_settings::SettingsObserver, search::SearchQuery,
|
||||
worktree_store::WorktreeStore, LspStore, ProjectPath, WorktreeId,
|
||||
buffer_store::{BufferStore, BufferStoreEvent},
|
||||
project_settings::SettingsObserver,
|
||||
search::SearchQuery,
|
||||
worktree_store::WorktreeStore,
|
||||
LspStore, ProjectPath, WorktreeId,
|
||||
};
|
||||
use remote::SshSession;
|
||||
use rpc::{
|
||||
|
@ -26,6 +29,7 @@ pub struct HeadlessProject {
|
|||
pub lsp_store: Model<LspStore>,
|
||||
pub settings_observer: Model<SettingsObserver>,
|
||||
pub next_entry_id: Arc<AtomicUsize>,
|
||||
pub languages: Arc<LanguageRegistry>,
|
||||
}
|
||||
|
||||
impl HeadlessProject {
|
||||
|
@ -60,7 +64,7 @@ impl HeadlessProject {
|
|||
buffer_store.clone(),
|
||||
worktree_store.clone(),
|
||||
environment,
|
||||
languages,
|
||||
languages.clone(),
|
||||
None,
|
||||
fs.clone(),
|
||||
cx,
|
||||
|
@ -69,6 +73,17 @@ impl HeadlessProject {
|
|||
lsp_store
|
||||
});
|
||||
|
||||
cx.subscribe(
|
||||
&buffer_store,
|
||||
|_this, _buffer_store, event, cx| match event {
|
||||
BufferStoreEvent::BufferAdded(buffer) => {
|
||||
cx.subscribe(buffer, Self::on_buffer_event).detach();
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
)
|
||||
.detach();
|
||||
|
||||
let client: AnyProtoClient = session.clone().into();
|
||||
|
||||
session.subscribe_to_entity(SSH_PROJECT_ID, &worktree_store);
|
||||
|
@ -103,6 +118,26 @@ impl HeadlessProject {
|
|||
buffer_store,
|
||||
lsp_store,
|
||||
next_entry_id: Default::default(),
|
||||
languages,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_buffer_event(
|
||||
&mut self,
|
||||
buffer: Model<Buffer>,
|
||||
event: &BufferEvent,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
BufferEvent::Operation(op) => cx
|
||||
.background_executor()
|
||||
.spawn(self.session.request(proto::UpdateBuffer {
|
||||
project_id: SSH_PROJECT_ID,
|
||||
buffer_id: buffer.read(cx).remote_id().to_proto(),
|
||||
operations: vec![serialize_operation(op)],
|
||||
}))
|
||||
.detach(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,9 @@ use gpui::{Context, Model, TestAppContext};
|
|||
use http_client::FakeHttpClient;
|
||||
use language::{
|
||||
language_settings::{all_language_settings, AllLanguageSettings},
|
||||
Buffer, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageRegistry,
|
||||
Buffer, FakeLspAdapter, LanguageConfig, LanguageMatcher, LanguageRegistry, LanguageServerName,
|
||||
};
|
||||
use lsp::{CompletionContext, CompletionResponse, CompletionTriggerKind};
|
||||
use node_runtime::FakeNodeRuntime;
|
||||
use project::{
|
||||
search::{SearchQuery, SearchResult},
|
||||
|
@ -317,6 +318,15 @@ async fn test_remote_lsp(cx: &mut TestAppContext, server_cx: &mut TestAppContext
|
|||
},
|
||||
)
|
||||
});
|
||||
|
||||
let mut fake_lsp = server_cx.update(|cx| {
|
||||
headless.read(cx).languages.register_fake_language_server(
|
||||
LanguageServerName("rust-analyzer".into()),
|
||||
Default::default(),
|
||||
None,
|
||||
)
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
let worktree_id = project
|
||||
|
@ -339,6 +349,8 @@ async fn test_remote_lsp(cx: &mut TestAppContext, server_cx: &mut TestAppContext
|
|||
.unwrap();
|
||||
cx.run_until_parked();
|
||||
|
||||
let fake_lsp = fake_lsp.next().await.unwrap();
|
||||
|
||||
cx.read(|cx| {
|
||||
let file = buffer.read(cx).file();
|
||||
assert_eq!(
|
||||
|
@ -370,6 +382,62 @@ async fn test_remote_lsp(cx: &mut TestAppContext, server_cx: &mut TestAppContext
|
|||
let lsp_store = headless.read(cx).lsp_store.read(cx);
|
||||
assert_eq!(lsp_store.as_local().unwrap().language_servers.len(), 1);
|
||||
});
|
||||
|
||||
fake_lsp.handle_request::<lsp::request::Completion, _, _>(|_, _| async move {
|
||||
Ok(Some(CompletionResponse::Array(vec![lsp::CompletionItem {
|
||||
label: "boop".to_string(),
|
||||
..Default::default()
|
||||
}])))
|
||||
});
|
||||
|
||||
let result = project
|
||||
.update(cx, |project, cx| {
|
||||
project.completions(
|
||||
&buffer,
|
||||
0,
|
||||
CompletionContext {
|
||||
trigger_kind: CompletionTriggerKind::INVOKED,
|
||||
trigger_character: None,
|
||||
},
|
||||
cx,
|
||||
)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
result.into_iter().map(|c| c.label.text).collect::<Vec<_>>(),
|
||||
vec!["boop".to_string()]
|
||||
);
|
||||
|
||||
fake_lsp.handle_request::<lsp::request::Rename, _, _>(|_, _| async move {
|
||||
Ok(Some(lsp::WorkspaceEdit {
|
||||
changes: Some(
|
||||
[(
|
||||
lsp::Url::from_file_path("/code/project1/src/lib.rs").unwrap(),
|
||||
vec![lsp::TextEdit::new(
|
||||
lsp::Range::new(lsp::Position::new(0, 3), lsp::Position::new(0, 6)),
|
||||
"two".to_string(),
|
||||
)],
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
),
|
||||
..Default::default()
|
||||
}))
|
||||
});
|
||||
|
||||
project
|
||||
.update(cx, |project, cx| {
|
||||
project.perform_rename(buffer.clone(), 3, "two".to_string(), true, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
buffer.update(cx, |buffer, _| {
|
||||
assert_eq!(buffer.text(), "fn two() -> usize { 1 }")
|
||||
})
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue