Refactor StdBackend to improve file watcher reliability

- Updated the `StdBackend` to utilize `notify::RecommendedWatcher` instead of a platform-specific watcher type, enhancing cross-platform event delivery.
- Simplified the debouncer initialization by removing platform-specific configurations, streamlining the code for better maintainability.
- Improved documentation to reflect changes in the watcher implementation and clarify the debouncing mechanism.
This commit is contained in:
Joe 2026-02-06 14:17:14 -06:00
parent 0605d5cfee
commit cf33a93640

View file

@ -5,19 +5,11 @@ use std::{collections::HashSet, io};
use crossbeam_channel::{Receiver, Sender}; use crossbeam_channel::{Receiver, Sender};
use notify::RecursiveMode; use notify::RecursiveMode;
use notify_debouncer_full::{ use notify_debouncer_full::{
new_debouncer_opt, new_debouncer,
notify::event::{CreateKind, EventKind, ModifyKind, RemoveKind, RenameMode}, notify::event::{CreateKind, EventKind, ModifyKind, RemoveKind, RenameMode},
DebounceEventResult, Debouncer, FileIdMap, DebounceEventResult, Debouncer, RecommendedCache,
}; };
/// 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}; use crate::{DirEntry, Metadata, ReadDir, VfsBackend, VfsEvent};
/// Critical errors from the file watcher that indicate watching is no longer reliable. /// Critical errors from the file watcher that indicate watching is no longer reliable.
@ -63,7 +55,7 @@ pub type CriticalErrorHandler = Box<dyn Fn(WatcherCriticalError) -> bool + Send
/// `VfsBackend` that uses `std::fs` and the `notify` crate. /// `VfsBackend` that uses `std::fs` and the `notify` crate.
pub struct StdBackend { pub struct StdBackend {
debouncer: Debouncer<PlatformWatcher, FileIdMap>, debouncer: Debouncer<notify::RecommendedWatcher, RecommendedCache>,
watcher_receiver: Receiver<VfsEvent>, watcher_receiver: Receiver<VfsEvent>,
watches: HashSet<PathBuf>, watches: HashSet<PathBuf>,
/// Receiver for critical errors from the watcher thread. /// Receiver for critical errors from the watcher thread.
@ -106,15 +98,11 @@ impl StdBackend {
event_tx: Sender<VfsEvent>, event_tx: Sender<VfsEvent>,
error_tx: Sender<WatcherCriticalError>, error_tx: Sender<WatcherCriticalError>,
error_handler: CriticalErrorHandler, error_handler: CriticalErrorHandler,
) -> Debouncer<PlatformWatcher, FileIdMap> { ) -> Debouncer<notify::RecommendedWatcher, RecommendedCache> {
// Use 50ms debounce timeout (same as the old v4 implementation) // Use 50ms debounce timeout (same as the old v4 implementation)
let debounce_timeout = Duration::from_millis(50); let debounce_timeout = Duration::from_millis(50);
// On macOS we use PollWatcher which needs an explicit poll interval. new_debouncer(
// 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, debounce_timeout,
None, // Use default tick rate None, // Use default tick rate
move |result: DebounceEventResult| { move |result: DebounceEventResult| {
@ -157,8 +145,6 @@ impl StdBackend {
} }
} }
}, },
FileIdMap::new(),
config,
) )
.expect("Failed to create file watcher debouncer") .expect("Failed to create file watcher debouncer")
} }