Fix hot reload of builtin TreeSitter queries on Linux (#37825)

Michael Sloan created

`fs.watch` is recursive on mac and non-recursive on Linux.

Release Notes:

- N/A

Change summary

crates/zed/src/main.rs | 35 ++++++++++++++++++++---------------
1 file changed, 20 insertions(+), 15 deletions(-)

Detailed changes

crates/zed/src/main.rs 🔗

@@ -1419,30 +1419,35 @@ fn watch_themes(fs: Arc<dyn fs::Fs>, cx: &mut App) {
 fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>, cx: &mut App) {
     use std::time::Duration;
 
-    let path = {
-        let p = Path::new("crates/languages/src");
-        let Ok(full_path) = p.canonicalize() else {
+    cx.background_spawn(async move {
+        let languages_src = Path::new("crates/languages/src");
+        let Some(languages_src) = fs.canonicalize(languages_src).await.log_err() else {
             return;
         };
-        full_path
-    };
 
-    cx.spawn(async move |_| {
-        let (mut events, _) = fs.watch(path.as_path(), Duration::from_millis(100)).await;
+        let (mut events, watcher) = fs.watch(&languages_src, Duration::from_millis(100)).await;
+
+        // add subdirectories since fs.watch is not recursive on Linux
+        if let Some(mut paths) = fs.read_dir(&languages_src).await.log_err() {
+            while let Some(path) = paths.next().await {
+                if let Some(path) = path.log_err()
+                    && fs.is_dir(&path).await
+                {
+                    watcher.add(&path).log_err();
+                }
+            }
+        }
+
         while let Some(event) = events.next().await {
-            let has_language_file = event.iter().any(|event| {
-                event
-                    .path
-                    .extension()
-                    .map(|ext| ext.to_string_lossy().as_ref() == "scm")
-                    .unwrap_or(false)
-            });
+            let has_language_file = event
+                .iter()
+                .any(|event| event.path.extension().is_some_and(|ext| ext == "scm"));
             if has_language_file {
                 languages.reload();
             }
         }
     })
-    .detach()
+    .detach();
 }
 
 #[cfg(not(debug_assertions))]