linux: Don't watch parent directory when target path already exists (#21854)

Cole Miller created

The Linux watcher was unconditionally watching the parent directory of
every watched path. This is needed in the case of config files that may
not exist when the watch is set up, but not in other cases. Scoping the
parent watch more narrowly cuts down on the amount of error logging from
irrelevant file change notifications being sent to Zed (in my case it
was picking up changes to a random file in `$HOME`).

Release Notes:

- N/A

Change summary

Cargo.lock           |  1 +
crates/fs/Cargo.toml |  1 +
crates/fs/src/fs.rs  | 11 +++++++----
3 files changed, 9 insertions(+), 4 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -4787,6 +4787,7 @@ dependencies = [
  "git2",
  "gpui",
  "libc",
+ "log",
  "notify",
  "objc",
  "parking_lot",

crates/fs/Cargo.toml 🔗

@@ -21,6 +21,7 @@ git.workspace = true
 git2.workspace = true
 gpui.workspace = true
 libc.workspace = true
+log.workspace = true
 parking_lot.workspace = true
 paths.workspace = true
 rope.workspace = true

crates/fs/src/fs.rs 🔗

@@ -695,10 +695,13 @@ impl Fs for RealFs {
         let pending_paths: Arc<Mutex<Vec<PathEvent>>> = Default::default();
         let watcher = Arc::new(linux_watcher::LinuxWatcher::new(tx, pending_paths.clone()));
 
-        watcher.add(&path).ok(); // Ignore "file doesn't exist error" and rely on parent watcher.
-        if let Some(parent) = path.parent() {
-            // watch the parent dir so we can tell when settings.json is created
-            watcher.add(parent).log_err();
+        if watcher.add(path).is_err() {
+            // If the path doesn't exist yet (e.g. settings.json), watch the parent dir to learn when it's created.
+            if let Some(parent) = path.parent() {
+                if let Err(e) = watcher.add(parent) {
+                    log::warn!("Failed to watch: {e}");
+                }
+            }
         }
 
         // Check if path is a symlink and follow the target parent