From 4bda5c4d696b8d6abeb2e8ccd85e3bf38e0b74d5 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 18 May 2023 17:08:51 -0700 Subject: [PATCH] Optimize LSP watched file reporting in 2 simple ways * Convert globs to relative paths in advance. This avoids needing to convert every changed path to an absolute path before performing glob matching. * Avoid duplicate reporting for language servers with multiple worktrees. --- crates/project/src/lsp_glob_set.rs | 8 +++++ crates/project/src/project.rs | 54 +++++++++++++++++++++++------- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/crates/project/src/lsp_glob_set.rs b/crates/project/src/lsp_glob_set.rs index daac344a0a..d4d661b6a1 100644 --- a/crates/project/src/lsp_glob_set.rs +++ b/crates/project/src/lsp_glob_set.rs @@ -73,6 +73,14 @@ impl LspGlobSet { } } +impl std::fmt::Debug for LspGlobSet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_set() + .entries(self.patterns.iter().map(|p| p.as_str())) + .finish() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 13809622f9..23b4984e55 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -226,7 +226,7 @@ pub enum LanguageServerState { language: Arc, adapter: Arc, server: Arc, - watched_paths: LspGlobSet, + watched_paths: HashMap, simulate_disk_based_diagnostics_completion: Option>, }, } @@ -2869,7 +2869,25 @@ impl Project { { watched_paths.clear(); for watcher in params.watchers { - watched_paths.add_pattern(&watcher.glob_pattern).log_err(); + for worktree in &self.worktrees { + if let Some(worktree) = worktree.upgrade(cx) { + let worktree = worktree.read(cx); + if let Some(abs_path) = worktree.abs_path().to_str() { + if let Some(suffix) = watcher + .glob_pattern + .strip_prefix(abs_path) + .and_then(|s| s.strip_prefix(std::path::MAIN_SEPARATOR)) + { + watched_paths + .entry(worktree.id()) + .or_default() + .add_pattern(suffix) + .log_err(); + break; + } + } + } + } } cx.notify(); } @@ -4708,24 +4726,34 @@ impl Project { cx: &mut ModelContext, ) { let worktree_id = worktree_handle.read(cx).id(); + let mut language_server_ids = self + .language_server_ids + .iter() + .filter_map(|((server_worktree_id, _), server_id)| { + (*server_worktree_id == worktree_id).then_some(*server_id) + }) + .collect::>(); + language_server_ids.sort(); + language_server_ids.dedup(); + let abs_path = worktree_handle.read(cx).abs_path(); - for ((server_worktree_id, _), server_id) in &self.language_server_ids { - if *server_worktree_id == worktree_id { - if let Some(server) = self.language_servers.get(server_id) { - if let LanguageServerState::Running { - server, - watched_paths, - .. - } = server - { + for server_id in &language_server_ids { + if let Some(server) = self.language_servers.get(server_id) { + if let LanguageServerState::Running { + server, + watched_paths, + .. + } = server + { + if let Some(watched_paths) = watched_paths.get(&worktree_id) { let params = lsp::DidChangeWatchedFilesParams { changes: changes .iter() .filter_map(|((path, _), change)| { - let path = abs_path.join(path); if watched_paths.matches(&path) { Some(lsp::FileEvent { - uri: lsp::Url::from_file_path(path).unwrap(), + uri: lsp::Url::from_file_path(abs_path.join(path)) + .unwrap(), typ: match change { PathChange::Added => lsp::FileChangeType::CREATED, PathChange::Removed => lsp::FileChangeType::DELETED,