diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 9dd27b1a31..c13426e8f1 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -55,9 +55,9 @@ use language::{ use log::error; use lsp::{ DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, - DocumentHighlightKind, Edit, LanguageServer, LanguageServerBinary, LanguageServerId, - LspRequestFuture, MessageActionItem, OneOf, ServerCapabilities, ServerHealthStatus, - ServerStatus, TextEdit, + DocumentHighlightKind, Edit, FileSystemWatcher, LanguageServer, LanguageServerBinary, + LanguageServerId, LspRequestFuture, MessageActionItem, OneOf, ServerCapabilities, + ServerHealthStatus, ServerStatus, TextEdit, }; use lsp_command::*; use node_runtime::NodeRuntime; @@ -167,6 +167,8 @@ pub struct Project { last_formatting_failure: Option, last_workspace_edits_by_language_server: HashMap, language_server_watched_paths: HashMap>, + language_server_watcher_registrations: + HashMap>>, client: Arc, next_entry_id: Arc, join_project_response_message_id: u32, @@ -725,6 +727,7 @@ impl Project { last_formatting_failure: None, last_workspace_edits_by_language_server: Default::default(), language_server_watched_paths: HashMap::default(), + language_server_watcher_registrations: HashMap::default(), buffers_being_formatted: Default::default(), buffers_needing_diff: Default::default(), git_diff_debouncer: DebouncedDelay::new(), @@ -875,6 +878,7 @@ impl Project { last_formatting_failure: None, last_workspace_edits_by_language_server: Default::default(), language_server_watched_paths: HashMap::default(), + language_server_watcher_registrations: HashMap::default(), opened_buffers: Default::default(), buffers_being_formatted: Default::default(), buffers_needing_diff: Default::default(), @@ -3471,7 +3475,7 @@ impl Project { let options = serde_json::from_value(options)?; this.update(&mut cx, |this, cx| { this.on_lsp_did_change_watched_files( - server_id, options, cx, + server_id, ®.id, options, cx, ); })?; } @@ -3483,6 +3487,27 @@ impl Project { }) .detach(); + language_server + .on_request::({ + let this = this.clone(); + move |params, mut cx| { + let this = this.clone(); + async move { + for unreg in params.unregisterations.iter() { + if unreg.method == "workspace/didChangeWatchedFiles" { + this.update(&mut cx, |this, cx| { + this.on_lsp_unregister_did_change_watched_files( + server_id, &unreg.id, cx, + ); + })?; + } + } + Ok(()) + } + } + }) + .detach(); + language_server .on_request::({ let adapter = adapter.clone(); @@ -4208,16 +4233,67 @@ impl Project { fn on_lsp_did_change_watched_files( &mut self, language_server_id: LanguageServerId, + registration_id: &str, params: DidChangeWatchedFilesRegistrationOptions, cx: &mut ModelContext, ) { + let registrations = self + .language_server_watcher_registrations + .entry(language_server_id) + .or_default(); + + registrations.insert(registration_id.to_string(), params.watchers); + + self.rebuild_watched_paths(language_server_id, cx); + } + + fn on_lsp_unregister_did_change_watched_files( + &mut self, + language_server_id: LanguageServerId, + registration_id: &str, + cx: &mut ModelContext, + ) { + let registrations = self + .language_server_watcher_registrations + .entry(language_server_id) + .or_default(); + + if registrations.remove(registration_id).is_some() { + log::info!( + "language server {}: unregistered workspace/DidChangeWatchedFiles capability with id {}", + language_server_id, + registration_id + ); + } else { + log::warn!( + "language server {}: failed to unregister workspace/DidChangeWatchedFiles capability with id {}. not registered.", + language_server_id, + registration_id + ); + } + + self.rebuild_watched_paths(language_server_id, cx); + } + + fn rebuild_watched_paths( + &mut self, + language_server_id: LanguageServerId, + cx: &mut ModelContext, + ) { + let Some(watchers) = self + .language_server_watcher_registrations + .get(&language_server_id) + else { + return; + }; + let watched_paths = self .language_server_watched_paths .entry(language_server_id) .or_default(); let mut builders = HashMap::default(); - for watcher in params.watchers { + for watcher in watchers.values().flatten() { for worktree in &self.worktrees { if let Some(worktree) = worktree.upgrade() { let glob_is_inside_worktree = worktree.update(cx, |tree, _| {