Revert "Debounce language server file system events (#30773)" (#31008)

Kirill Bulatov created

Let's keep https://github.com/zed-industries/zed/pull/30773 and its
complexity out of Zed sources if we can:
https://github.com/rust-lang/rust-analyzer/pull/19814 seems to do a
similar thing and might have fixed the root cause.

If not, we can always reapply this later after ensuring.

Release Notes:

- N/A

Change summary

crates/project/src/lsp_store.rs     | 76 +++++++-----------------------
crates/project/src/project_tests.rs |  7 --
2 files changed, 20 insertions(+), 63 deletions(-)

Detailed changes

crates/project/src/lsp_store.rs 🔗

@@ -104,7 +104,6 @@ pub use worktree::{
 
 const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5);
 pub const SERVER_PROGRESS_THROTTLE_TIMEOUT: Duration = Duration::from_millis(100);
-pub const FS_WATCH_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(500);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum FormatTrigger {
@@ -9221,9 +9220,7 @@ impl LspStore {
             return;
         }
 
-        let Some(local) = self.as_local_mut() else {
-            return;
-        };
+        let Some(local) = self.as_local() else { return };
 
         local.prettier_store.update(cx, |prettier_store, cx| {
             prettier_store.update_prettier_settings(&worktree_handle, changes, cx)
@@ -9243,53 +9240,22 @@ impl LspStore {
         language_server_ids.dedup();
 
         let abs_path = worktree_handle.read(cx).abs_path();
-
         for server_id in &language_server_ids {
-            let Some(watch) = local.language_server_watched_paths.get_mut(&server_id) else {
-                continue;
-            };
-            let Some(watched_paths) = watch.worktree_paths.get(&worktree_id) else {
-                continue;
-            };
-
-            for (path, _, change) in changes {
-                if !watched_paths.is_match(path) {
-                    continue;
-                }
-
-                let file_abs_path = abs_path.join(path);
-
-                watch.pending_events.insert(file_abs_path, *change);
-            }
-
-            if watch.pending_events.is_empty() {
-                continue;
-            }
-            let server_id = *server_id;
-
-            watch.flush_timer_task = Some(cx.spawn(async move |this, cx| {
-                cx.background_executor()
-                    .timer(FS_WATCH_DEBOUNCE_TIMEOUT)
-                    .await;
-                this.update(cx, |this, _cx| {
-                    let Some(this) = this.as_local_mut() else {
-                        return;
-                    };
-                    let Some(LanguageServerState::Running { server, .. }) =
-                        this.language_servers.get(&server_id)
-                    else {
-                        return;
-                    };
-
-                    let Some(watch) = this.language_server_watched_paths.get_mut(&server_id) else {
-                        return;
-                    };
-
+            if let Some(LanguageServerState::Running { server, .. }) =
+                local.language_servers.get(server_id)
+            {
+                if let Some(watched_paths) = local
+                    .language_server_watched_paths
+                    .get(server_id)
+                    .and_then(|paths| paths.worktree_paths.get(&worktree_id))
+                {
                     let params = lsp::DidChangeWatchedFilesParams {
-                        changes: watch
-                            .pending_events
-                            .drain()
-                            .filter_map(|(path, change)| {
+                        changes: changes
+                            .iter()
+                            .filter_map(|(path, _, change)| {
+                                if !watched_paths.is_match(path) {
+                                    return None;
+                                }
                                 let typ = match change {
                                     PathChange::Loaded => return None,
                                     PathChange::Added => lsp::FileChangeType::CREATED,
@@ -9298,21 +9264,19 @@ impl LspStore {
                                     PathChange::AddedOrUpdated => lsp::FileChangeType::CHANGED,
                                 };
                                 Some(lsp::FileEvent {
-                                    uri: lsp::Url::from_file_path(&path).unwrap(),
+                                    uri: lsp::Url::from_file_path(abs_path.join(path)).unwrap(),
                                     typ,
                                 })
                             })
                             .collect(),
                     };
-
                     if !params.changes.is_empty() {
                         server
                             .notify::<lsp::notification::DidChangeWatchedFiles>(&params)
                             .ok();
                     }
-                })
-                .log_err();
-            }));
+                }
+            }
         }
     }
 
@@ -9757,8 +9721,6 @@ impl RenameActionPredicate {
 #[derive(Default)]
 struct LanguageServerWatchedPaths {
     worktree_paths: HashMap<WorktreeId, GlobSet>,
-    pending_events: HashMap<PathBuf, PathChange>,
-    flush_timer_task: Option<Task<()>>,
     abs_paths: HashMap<Arc<Path>, (GlobSet, Task<()>)>,
 }
 
@@ -9837,8 +9799,6 @@ impl LanguageServerWatchedPathsBuilder {
             .collect();
         LanguageServerWatchedPaths {
             worktree_paths: self.worktree_paths,
-            pending_events: HashMap::default(),
-            flush_timer_task: None,
             abs_paths,
         }
     }

crates/project/src/project_tests.rs 🔗

@@ -1,8 +1,8 @@
 #![allow(clippy::format_collect)]
 
 use crate::{
-    Event, git_store::StatusEntry, lsp_store::FS_WATCH_DEBOUNCE_TIMEOUT,
-    task_inventory::TaskContexts, task_store::TaskSettingsLocation, *,
+    Event, git_store::StatusEntry, task_inventory::TaskContexts, task_store::TaskSettingsLocation,
+    *,
 };
 use buffer_diff::{
     BufferDiffEvent, CALCULATE_DIFF_TASK, DiffHunkSecondaryStatus, DiffHunkStatus,
@@ -1190,9 +1190,6 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
 
     // The language server receives events for the FS mutations that match its watch patterns.
     cx.executor().run_until_parked();
-    cx.executor().advance_clock(FS_WATCH_DEBOUNCE_TIMEOUT);
-    cx.executor().run_until_parked();
-
     assert_eq!(
         &*file_changes.lock(),
         &[