diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index bd6ac7588..3bc324395 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -704,28 +704,10 @@ impl Application { language_server.did_change_configuration(config.clone()); } - let docs = self - .editor - .documents() - .filter(|doc| doc.supports_language_server(server_id)); - - // trigger textDocument/didOpen for docs that are already open - for doc in docs { - let url = match doc.url() { - Some(url) => url, - None => continue, // skip documents with no path - }; - - let language_id = - doc.language_id().map(ToOwned::to_owned).unwrap_or_default(); - - language_server.text_document_did_open( - url, - doc.version(), - doc.text(), - language_id, - ); - } + helix_event::dispatch(helix_view::events::LanguageServerInitialized { + editor: &mut self.editor, + server_id, + }); } Notification::PublishDiagnostics(params) => { let uri = match helix_core::Uri::try_from(params.uri) { @@ -870,6 +852,11 @@ impl Application { doc.clear_diagnostics_for_language_server(server_id); } + helix_event::dispatch(helix_view::events::LanguageServerExited { + editor: &mut self.editor, + server_id, + }); + // Remove the language server from the registry. self.editor.language_servers.remove_by_id(server_id); } diff --git a/helix-term/src/events.rs b/helix-term/src/events.rs index 15d811529..80f045cd7 100644 --- a/helix-term/src/events.rs +++ b/helix-term/src/events.rs @@ -1,7 +1,8 @@ use helix_event::{events, register_event}; use helix_view::document::Mode; use helix_view::events::{ - DiagnosticsDidChange, DocumentDidChange, DocumentFocusLost, SelectionDidChange, + DiagnosticsDidChange, DocumentDidChange, DocumentDidClose, DocumentDidOpen, DocumentFocusLost, + LanguageServerExited, LanguageServerInitialized, SelectionDidChange, }; use crate::commands; @@ -17,8 +18,12 @@ pub fn register() { register_event::(); register_event::(); register_event::(); + register_event::(); register_event::(); + register_event::(); register_event::(); register_event::(); register_event::(); + register_event::(); + register_event::(); } diff --git a/helix-term/src/handlers.rs b/helix-term/src/handlers.rs index b580e678b..24d8491b1 100644 --- a/helix-term/src/handlers.rs +++ b/helix-term/src/handlers.rs @@ -29,6 +29,7 @@ pub fn setup(config: Arc>) -> Handlers { auto_save, }; + helix_view::handlers::register_hooks(&handlers); completion::register_hooks(&handlers); signature_help::register_hooks(&handlers); auto_save::register_hooks(&handlers); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index f74f15c6e..9b3b45486 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1489,19 +1489,6 @@ impl Document { }); } - if emit_lsp_notification { - // TODO: move to hook - // emit lsp notification - for language_server in self.language_servers() { - let _ = language_server.text_document_did_change( - self.versioned_identifier(), - &old_doc, - self.text(), - changes, - ); - } - } - true } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 31373630d..723fb1392 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -4,7 +4,7 @@ use crate::{ document::{ DocumentOpenError, DocumentSavedEventFuture, DocumentSavedEventResult, Mode, SavePoint, }, - events::DocumentFocusLost, + events::{DocumentDidClose, DocumentDidOpen, DocumentFocusLost}, graphics::{CursorKind, Rect}, handlers::Handlers, info::Info, @@ -1783,10 +1783,16 @@ impl Editor { let id = self.new_document(doc); self.launch_language_servers(id); + helix_event::dispatch(DocumentDidOpen { + editor: self, + doc: id, + }); + id }; self.switch(id, action); + Ok(id) } @@ -1800,7 +1806,7 @@ impl Editor { } pub fn close_document(&mut self, doc_id: DocumentId, force: bool) -> Result<(), CloseError> { - let doc = match self.documents.get_mut(&doc_id) { + let doc = match self.documents.remove(&doc_id) { Some(doc) => doc, None => return Err(CloseError::DoesNotExist), }; @@ -1811,10 +1817,6 @@ impl Editor { // This will also disallow any follow-up writes self.saves.remove(&doc_id); - for language_server in doc.language_servers() { - language_server.text_document_did_close(doc.identifier()); - } - enum Action { Close(ViewId), ReplaceDoc(ViewId, DocumentId), @@ -1851,8 +1853,6 @@ impl Editor { } } - self.documents.remove(&doc_id); - // If the document we removed was visible in all views, we will have no more views. We don't // want to close the editor just for a simple buffer close, so we need to create a new view // containing either an existing document, or a brand new document. @@ -1872,6 +1872,8 @@ impl Editor { self._refresh(); + helix_event::dispatch(DocumentDidClose { editor: self, doc }); + Ok(()) } diff --git a/helix-view/src/events.rs b/helix-view/src/events.rs index eb97268ce..4a44beb35 100644 --- a/helix-view/src/events.rs +++ b/helix-view/src/events.rs @@ -1,9 +1,14 @@ use helix_core::{ChangeSet, Rope}; use helix_event::events; +use helix_lsp::LanguageServerId; use crate::{Document, DocumentId, Editor, ViewId}; events! { + DocumentDidOpen<'a> { + editor: &'a mut Editor, + doc: DocumentId + } DocumentDidChange<'a> { doc: &'a mut Document, view: ViewId, @@ -11,8 +16,21 @@ events! { changes: &'a ChangeSet, ghost_transaction: bool } + DocumentDidClose<'a> { + editor: &'a mut Editor, + doc: Document + } SelectionDidChange<'a> { doc: &'a mut Document, view: ViewId } DiagnosticsDidChange<'a> { editor: &'a mut Editor, doc: DocumentId } // called **after** a document loses focus (but not when its closed) DocumentFocusLost<'a> { editor: &'a mut Editor, doc: DocumentId } + + LanguageServerInitialized<'a> { + editor: &'a mut Editor, + server_id: LanguageServerId + } + LanguageServerExited<'a> { + editor: &'a mut Editor, + server_id: LanguageServerId + } } diff --git a/helix-view/src/handlers.rs b/helix-view/src/handlers.rs index a26c4ddb1..86217c23b 100644 --- a/helix-view/src/handlers.rs +++ b/helix-view/src/handlers.rs @@ -46,3 +46,7 @@ impl Handlers { send_blocking(&self.signature_hints, event) } } + +pub fn register_hooks(handlers: &Handlers) { + lsp::register_hooks(handlers); +} diff --git a/helix-view/src/handlers/lsp.rs b/helix-view/src/handlers/lsp.rs index 14e37c155..813885408 100644 --- a/helix-view/src/handlers/lsp.rs +++ b/helix-view/src/handlers/lsp.rs @@ -2,13 +2,18 @@ use std::collections::btree_map::Entry; use std::fmt::Display; use crate::editor::Action; -use crate::events::DiagnosticsDidChange; +use crate::events::{ + DiagnosticsDidChange, DocumentDidChange, DocumentDidClose, LanguageServerInitialized, +}; use crate::Editor; use helix_core::diagnostic::DiagnosticProvider; use helix_core::Uri; +use helix_event::register_hook; use helix_lsp::util::generate_transaction_from_edits; use helix_lsp::{lsp, LanguageServerId, OffsetEncoding}; +use super::Handlers; + #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum SignatureHelpInvoked { Automatic, @@ -381,3 +386,50 @@ impl Editor { }); } } + +pub fn register_hooks(_handlers: &Handlers) { + register_hook!(move |event: &mut LanguageServerInitialized<'_>| { + let language_server = event.editor.language_server_by_id(event.server_id).unwrap(); + + for doc in event + .editor + .documents() + .filter(|doc| doc.supports_language_server(event.server_id)) + { + let Some(url) = doc.url() else { + continue; + }; + + let language_id = doc.language_id().map(ToOwned::to_owned).unwrap_or_default(); + + language_server.text_document_did_open(url, doc.version(), doc.text(), language_id); + } + + Ok(()) + }); + + register_hook!(move |event: &mut DocumentDidChange<'_>| { + // Send textDocument/didChange notifications. + if !event.ghost_transaction { + for language_server in event.doc.language_servers() { + language_server.text_document_did_change( + event.doc.versioned_identifier(), + event.old_text, + event.doc.text(), + event.changes, + ); + } + } + + Ok(()) + }); + + register_hook!(move |event: &mut DocumentDidClose<'_>| { + // Send textDocument/didClose notifications. + for language_server in event.doc.language_servers() { + language_server.text_document_did_close(event.doc.identifier()); + } + + Ok(()) + }); +}