Refactor file watcher and path suppression handling for improved reliability

- Updated the `StdBackend` to use a platform-specific watcher type, enhancing event delivery on macOS by utilizing `PollWatcher`.
- Refactored the path suppression logic in `JobThreadContext` to handle any VFS event type, improving the accuracy of event processing during renames and writes.
- Enhanced documentation to clarify the changes in event handling and suppression mechanisms, contributing to better maintainability and understanding of the code.
This commit is contained in:
Joe 2026-02-06 13:58:59 -06:00
parent 4ee1e79a90
commit 0605d5cfee
2 changed files with 109 additions and 53 deletions

View file

@ -5,11 +5,19 @@ use std::{collections::HashSet, io};
use crossbeam_channel::{Receiver, Sender};
use notify::RecursiveMode;
use notify_debouncer_full::{
new_debouncer,
new_debouncer_opt,
notify::event::{CreateKind, EventKind, ModifyKind, RemoveKind, RenameMode},
DebounceEventResult, Debouncer, RecommendedCache,
DebounceEventResult, Debouncer, FileIdMap,
};
/// On macOS, FSEvents silently fails to deliver events in `/var/folders/`
/// temp directories (a known platform limitation). Use PollWatcher instead
/// for reliable event delivery on all directory types.
#[cfg(target_os = "macos")]
type PlatformWatcher = notify::PollWatcher;
#[cfg(not(target_os = "macos"))]
type PlatformWatcher = notify::RecommendedWatcher;
use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent};
/// Critical errors from the file watcher that indicate watching is no longer reliable.
@ -55,7 +63,7 @@ pub type CriticalErrorHandler = Box<dyn Fn(WatcherCriticalError) -> bool + Send
/// `VfsBackend` that uses `std::fs` and the `notify` crate.
pub struct StdBackend {
debouncer: Debouncer<notify::RecommendedWatcher, RecommendedCache>,
debouncer: Debouncer<PlatformWatcher, FileIdMap>,
watcher_receiver: Receiver<VfsEvent>,
watches: HashSet<PathBuf>,
/// Receiver for critical errors from the watcher thread.
@ -98,11 +106,15 @@ impl StdBackend {
event_tx: Sender<VfsEvent>,
error_tx: Sender<WatcherCriticalError>,
error_handler: CriticalErrorHandler,
) -> Debouncer<notify::RecommendedWatcher, RecommendedCache> {
) -> Debouncer<PlatformWatcher, FileIdMap> {
// Use 50ms debounce timeout (same as the old v4 implementation)
let debounce_timeout = Duration::from_millis(50);
new_debouncer(
// On macOS we use PollWatcher which needs an explicit poll interval.
// On other platforms this field is ignored by RecommendedWatcher.
let config = notify::Config::default().with_poll_interval(debounce_timeout);
new_debouncer_opt::<_, PlatformWatcher, FileIdMap>(
debounce_timeout,
None, // Use default tick rate
move |result: DebounceEventResult| {
@ -145,6 +157,8 @@ impl StdBackend {
}
}
},
FileIdMap::new(),
config,
)
.expect("Failed to create file watcher debouncer")
}