lsp: Wait for shutdown response before sending exit notification (#33417)

Umesh Yadav created

Follow up: #18634

Closes #33328

Release Notes:

- Fixed language server shutdown process to prevent race conditions and
improper termination by waiting for shutdown confirmation before closing
connections.

Change summary

crates/lsp/src/lsp.rs  | 7 ++++---
crates/vim/src/test.rs | 4 ----
2 files changed, 4 insertions(+), 7 deletions(-)

Detailed changes

crates/lsp/src/lsp.rs 🔗

@@ -874,8 +874,6 @@ impl LanguageServer {
                 &executor,
                 (),
             );
-            let exit = Self::notify_internal::<notification::Exit>(&outbound_tx, &());
-            outbound_tx.close();
 
             let server = self.server.clone();
             let name = self.name.clone();
@@ -901,7 +899,8 @@ impl LanguageServer {
                     }
 
                     response_handlers.lock().take();
-                    exit?;
+                    Self::notify_internal::<notification::Exit>(&outbound_tx, &()).ok();
+                    outbound_tx.close();
                     output_done.recv().await;
                     server.lock().take().map(|mut child| child.kill());
                     log::debug!("language server shutdown finished");
@@ -1508,6 +1507,8 @@ impl FakeLanguageServer {
             }
         });
 
+        fake.set_request_handler::<request::Shutdown, _, _>(|_, _| async move { Ok(()) });
+
         (server, fake)
     }
     #[cfg(target_os = "windows")]

crates/vim/src/test.rs 🔗

@@ -1006,8 +1006,6 @@ async fn test_rename(cx: &mut gpui::TestAppContext) {
     cx.assert_state("const afterˇ = 2; console.log(after)", Mode::Normal)
 }
 
-// TODO: this test is flaky on our linux CI machines
-#[cfg(target_os = "macos")]
 #[gpui::test]
 async fn test_remap(cx: &mut gpui::TestAppContext) {
     let mut cx = VimTestContext::new(cx, true).await;
@@ -1048,8 +1046,6 @@ async fn test_remap(cx: &mut gpui::TestAppContext) {
     cx.simulate_keystrokes("g x");
     cx.assert_state("1234fooˇ56789", Mode::Normal);
 
-    cx.executor().allow_parking();
-
     // test command
     cx.update(|_, cx| {
         cx.bind_keys([KeyBinding::new(