Allow restarting remote language servers (#12652)

Conrad Irwin created

Release Notes:

- Added the ability to restart the remote language servers when
collaborating

Change summary

crates/collab/src/rpc.rs      |  3 ++
crates/project/src/project.rs | 38 ++++++++++++++++++++++++++++++++++--
crates/rpc/proto/zed.proto    |  8 ++++++
crates/rpc/src/proto.rs       |  5 +++
crates/text/src/text.rs       |  4 +++
5 files changed, 53 insertions(+), 5 deletions(-)

Detailed changes

crates/collab/src/rpc.rs 🔗

@@ -545,6 +545,9 @@ impl Server {
             .add_request_handler(user_handler(
                 forward_mutating_project_request::<proto::MultiLspQuery>,
             ))
+            .add_request_handler(user_handler(
+                forward_mutating_project_request::<proto::RestartLanguageServers>,
+            ))
             .add_message_handler(create_buffer_for_peer)
             .add_request_handler(update_buffer)
             .add_message_handler(broadcast_project_message_from_host::<proto::RefreshInlayHints>)

crates/project/src/project.rs 🔗

@@ -697,6 +697,7 @@ impl Project {
         client.add_model_request_handler(Self::handle_lsp_command::<lsp_ext_command::ExpandMacro>);
         client.add_model_request_handler(Self::handle_blame_buffer);
         client.add_model_request_handler(Self::handle_multi_lsp_query);
+        client.add_model_request_handler(Self::handle_restart_language_servers);
         client.add_model_request_handler(Self::handle_task_context_for_location);
         client.add_model_request_handler(Self::handle_task_templates);
     }
@@ -3976,11 +3977,44 @@ impl Project {
         }
     }
 
+    async fn handle_restart_language_servers(
+        project: Model<Self>,
+        envelope: TypedEnvelope<proto::RestartLanguageServers>,
+        _: Arc<Client>,
+        mut cx: AsyncAppContext,
+    ) -> Result<proto::Ack> {
+        project.update(&mut cx, |project, cx| {
+            let buffers: Vec<_> = envelope
+                .payload
+                .buffer_ids
+                .into_iter()
+                .flat_map(|buffer_id| project.buffer_for_id(BufferId::new(buffer_id).log_err()?))
+                .collect();
+            project.restart_language_servers_for_buffers(buffers, cx)
+        })?;
+
+        Ok(proto::Ack {})
+    }
+
     pub fn restart_language_servers_for_buffers(
         &mut self,
         buffers: impl IntoIterator<Item = Model<Buffer>>,
         cx: &mut ModelContext<Self>,
-    ) -> Option<()> {
+    ) {
+        if self.is_remote() {
+            let request = self.client.request(proto::RestartLanguageServers {
+                project_id: self.remote_id().unwrap(),
+                buffer_ids: buffers
+                    .into_iter()
+                    .map(|b| b.read(cx).remote_id().to_proto())
+                    .collect(),
+            });
+            cx.background_executor()
+                .spawn(request)
+                .detach_and_log_err(cx);
+            return;
+        }
+
         let language_server_lookup_info: HashSet<(Model<Worktree>, Arc<Language>)> = buffers
             .into_iter()
             .filter_map(|buffer| {
@@ -3998,8 +4032,6 @@ impl Project {
         for (worktree, language) in language_server_lookup_info {
             self.restart_language_servers(worktree, language, cx);
         }
-
-        None
     }
 
     fn restart_language_servers(

crates/rpc/proto/zed.proto 🔗

@@ -159,7 +159,7 @@ message Envelope {
         SetChannelMemberRole set_channel_member_role = 123;
         RenameChannel rename_channel = 124;
         RenameChannelResponse rename_channel_response = 125;
-        SubscribeToChannels subscribe_to_channels = 207; // current max
+        SubscribeToChannels subscribe_to_channels = 207;
 
         JoinChannelBuffer join_channel_buffer = 126;
         JoinChannelBufferResponse join_channel_buffer_response = 127;
@@ -220,6 +220,7 @@ message Envelope {
 
         MultiLspQuery multi_lsp_query = 175;
         MultiLspQueryResponse multi_lsp_query_response = 176;
+        RestartLanguageServers restart_language_servers = 208;  // current max
 
         CreateDevServerProject create_dev_server_project = 177;
         CreateDevServerProjectResponse create_dev_server_project_response = 188;
@@ -2110,6 +2111,11 @@ message MultiLspQuery {
 
 message AllLanguageServers {}
 
+message RestartLanguageServers {
+    uint64 project_id = 1;
+    repeated uint64 buffer_ids = 2;
+}
+
 message MultiLspQueryResponse {
     repeated LspResponse responses = 1;
 }

crates/rpc/src/proto.rs 🔗

@@ -332,6 +332,7 @@ messages!(
     (RegenerateDevServerTokenResponse, Foreground),
     (RenameDevServer, Foreground),
     (OpenNewBuffer, Foreground),
+    (RestartLanguageServers, Foreground),
 );
 
 request_messages!(
@@ -441,7 +442,8 @@ request_messages!(
     (DeleteDevServer, Ack),
     (DeleteDevServerProject, Ack),
     (RegenerateDevServerToken, RegenerateDevServerTokenResponse),
-    (RenameDevServer, Ack)
+    (RenameDevServer, Ack),
+    (RestartLanguageServers, Ack)
 );
 
 entity_messages!(
@@ -471,6 +473,7 @@ entity_messages!(
     JoinProject,
     LeaveProject,
     MultiLspQuery,
+    RestartLanguageServers,
     OnTypeFormatting,
     OpenNewBuffer,
     OpenBufferById,

crates/text/src/text.rs 🔗

@@ -91,6 +91,10 @@ impl BufferId {
         self.0 = self.0.saturating_add(1);
         old
     }
+
+    pub fn to_proto(self) -> u64 {
+        self.into()
+    }
 }
 impl From<BufferId> for u64 {
     fn from(id: BufferId) -> Self {