From 6d91fd078c391cea8b59ae8c83147ca138c91730 Mon Sep 17 00:00:00 2001 From: Keith Simmons Date: Tue, 29 Mar 2022 17:24:23 -0700 Subject: [PATCH] Add restart-lsp keybinding --- crates/editor/src/editor.rs | 16 +++++++++++ crates/language/src/language.rs | 2 ++ crates/lsp/src/lsp.rs | 21 ++++++++++++-- crates/project/src/project.rs | 46 +++++++++++++++++++++++++++++++ crates/workspace/src/workspace.rs | 6 ++++ 5 files changed, 88 insertions(+), 3 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index f861b6ac60b1f4fe2c1b8ca83df26fed4abf9d6f..5dab624a95c93e00e7a4ce3f9cbf30a6d4051c40 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -141,6 +141,7 @@ action!(ToggleCodeActions, bool); action!(ConfirmCompletion, Option); action!(ConfirmCodeAction, Option); action!(OpenExcerpts); +action!(RestartLanguageServer); enum DocumentHighlightRead {} enum DocumentHighlightWrite {} @@ -302,6 +303,7 @@ pub fn init(cx: &mut MutableAppContext) { Binding::new("ctrl-space", ShowCompletions, Some("Editor")), Binding::new("cmd-.", ToggleCodeActions(false), Some("Editor")), Binding::new("alt-enter", OpenExcerpts, Some("Editor")), + Binding::new("cmd-f10", RestartLanguageServer, Some("Editor")), ]); cx.add_action(Editor::open_new); @@ -377,6 +379,7 @@ pub fn init(cx: &mut MutableAppContext) { cx.add_action(Editor::show_completions); cx.add_action(Editor::toggle_code_actions); cx.add_action(Editor::open_excerpts); + cx.add_action(Editor::restart_language_server); cx.add_async_action(Editor::confirm_completion); cx.add_async_action(Editor::confirm_code_action); cx.add_async_action(Editor::rename); @@ -4867,6 +4870,19 @@ impl Editor { self.pending_rename.as_ref() } + fn restart_language_server(&mut self, _: &RestartLanguageServer, cx: &mut ViewContext) { + let project = self.project.clone(); + if let Some(project) = project { + self.buffer.update(cx, |multi_buffer, cx| { + for buffer in multi_buffer.all_buffers() { + project.update(cx, |project, cx| { + project.restart_language_server_for_buffer(&buffer, cx); + }); + } + }) + } + } + fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext) { if let Some(active_diagnostics) = self.active_diagnostics.as_mut() { let buffer = self.buffer.read(cx).snapshot(cx); diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 3fbc00c72d350c975222008cf9dc03015020ca26..8e5698a614f1bb34088ec62dcea39df365cd7dd8 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -245,6 +245,7 @@ impl LanguageRegistry { pub fn start_language_server( &self, + server_id: usize, language: Arc, root_path: Arc, http_client: Arc, @@ -324,6 +325,7 @@ impl LanguageRegistry { let server_binary_path = server_binary_path.await?; let server_args = adapter.server_args(); let server = lsp::LanguageServer::new( + server_id, &server_binary_path, server_args, &root_path, diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index fad49d2424017eea8f66308d2e061b02c9a41ffe..d5845bb87b3d200ca3f463d8623542d866d56bb6 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -34,6 +34,7 @@ type NotificationHandler = type ResponseHandler = Box)>; pub struct LanguageServer { + server_id: usize, next_id: AtomicUsize, outbound_tx: channel::Sender>, name: String, @@ -113,6 +114,7 @@ struct Error { impl LanguageServer { pub fn new( + server_id: usize, binary_path: &Path, args: &[&str], root_path: &Path, @@ -133,7 +135,8 @@ impl LanguageServer { .spawn()?; let stdin = server.stdin.take().unwrap(); let stdout = server.stdout.take().unwrap(); - let mut server = Self::new_internal(stdin, stdout, root_path, options, background); + let mut server = + Self::new_internal(server_id, stdin, stdout, root_path, options, background); if let Some(name) = binary_path.file_name() { server.name = name.to_string_lossy().to_string(); } @@ -141,6 +144,7 @@ impl LanguageServer { } fn new_internal( + server_id: usize, stdin: Stdin, stdout: Stdout, root_path: &Path, @@ -240,6 +244,7 @@ impl LanguageServer { }); Self { + server_id, notification_handlers, response_handlers, name: Default::default(), @@ -446,6 +451,10 @@ impl LanguageServer { &self.capabilities } + pub fn server_id(&self) -> usize { + self.server_id + } + pub fn request( self: &Arc, params: T::Params, @@ -606,8 +615,14 @@ impl LanguageServer { }); let executor = cx.background().clone(); - let server = - Self::new_internal(stdin_writer, stdout_reader, Path::new("/"), None, executor); + let server = Self::new_internal( + 0, + stdin_writer, + stdout_reader, + Path::new("/"), + None, + executor, + ); (server, fake) } } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 404d867069ec383c24dac33f550ac63306468122..c271477dd6ec4cc3b148853044a5c43aff91ea8c 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1308,6 +1308,7 @@ impl Project { .or_insert_with(|| { let server_id = post_inc(&mut self.next_language_server_id); let language_server = self.languages.start_language_server( + server_id, language.clone(), worktree_path, self.client.http_client(), @@ -1507,6 +1508,51 @@ impl Project { }); } + pub fn restart_language_server_for_buffer( + &mut self, + buffer: &ModelHandle, + cx: &mut ModelContext, + ) -> Option<()> { + let file = File::from_dyn(buffer.read(cx).file())?; + let worktree = file.worktree.read(cx).as_local()?; + let worktree_id = worktree.id(); + let worktree_abs_path = worktree.abs_path().clone(); + let full_path = buffer.read(cx).file()?.full_path(cx); + let language = self.languages.select_language(&full_path)?; + self.restart_language_server(worktree_id, worktree_abs_path, language, cx); + + None + } + + fn restart_language_server( + &mut self, + worktree_id: WorktreeId, + worktree_path: Arc, + language: Arc, + cx: &mut ModelContext, + ) { + let key = (worktree_id, language.name()); + let server_to_shutdown = self.language_servers.remove(&key); + self.started_language_servers.remove(&key); + server_to_shutdown + .as_ref() + .map(|server| self.language_server_statuses.remove(&server.server_id())); + cx.spawn_weak(|this, mut cx| async move { + if let Some(this) = this.upgrade(&cx) { + if let Some(server_to_shutdown) = server_to_shutdown { + if let Some(shutdown_task) = server_to_shutdown.shutdown() { + shutdown_task.await; + } + } + + this.update(&mut cx, |this, cx| { + this.start_language_server(worktree_id, worktree_path, language, cx); + }); + } + }) + .detach(); + } + fn on_lsp_event( &mut self, language_server_id: usize, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 17b0c4b51859b9f42acb2a513be6e3c2b94114ae..ccf52df6720aafffd69dc39bc86eff5b7a94d17e 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -80,6 +80,7 @@ action!(Save); action!(DebugElements); action!(ActivatePreviousPane); action!(ActivateNextPane); +action!(RestartLanguageServer); pub fn init(client: &Arc, cx: &mut MutableAppContext) { pane::init(cx); @@ -119,6 +120,9 @@ pub fn init(client: &Arc, cx: &mut MutableAppContext) { cx.add_action(|workspace: &mut Workspace, _: &ActivateNextPane, cx| { workspace.activate_next_pane(cx) }); + cx.add_action(|workspace: &mut Workspace, _: &RestartLanguageServer, cx| { + workspace.restart_language_server(cx) + }); cx.add_bindings(vec![ Binding::new("ctrl-alt-cmd-f", FollowNextCollaborator, None), Binding::new("cmd-s", Save, None), @@ -1419,6 +1423,8 @@ impl Workspace { None } + fn restart_language_server(&mut self, cx: &mut ViewContext) {} + fn render_connection_status(&self, cx: &mut RenderContext) -> Option { let theme = &cx.global::().theme; match &*self.client.status().borrow() {