windows: Fix fs watch when file doesn't exist or is a symlink (#22660)
Closes #22659 More context can be found in attached issue. This is specific to Windows: 1. Add parent directory watching for fs watch when the file doesn't exist. For example, when Zed is first launched and `settings.json` isn't there. 2. Add proper symlink handling for fs watch. For example, when `settings.json` is a symlink. This is exactly same as how we handle it on Linux. Release Notes: - Fixed an issue where items on the Welcome page could not be toggled on Windows, either on first launch or when `settings.json` is a symlink.
This commit is contained in:
parent
d58f006498
commit
d3fc00d5a0
4 changed files with 56 additions and 72 deletions
|
@ -1,8 +1,8 @@
|
|||
#[cfg(target_os = "macos")]
|
||||
mod mac_watcher;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
pub mod linux_watcher;
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub mod fs_watcher;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use git::GitHostingProviderRegistry;
|
||||
|
@ -700,7 +700,7 @@ impl Fs for RealFs {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
async fn watch(
|
||||
&self,
|
||||
path: &Path,
|
||||
|
@ -710,10 +710,11 @@ impl Fs for RealFs {
|
|||
Arc<dyn Watcher>,
|
||||
) {
|
||||
use parking_lot::Mutex;
|
||||
use util::paths::SanitizedPath;
|
||||
|
||||
let (tx, rx) = smol::channel::unbounded();
|
||||
let pending_paths: Arc<Mutex<Vec<PathEvent>>> = Default::default();
|
||||
let watcher = Arc::new(linux_watcher::LinuxWatcher::new(tx, pending_paths.clone()));
|
||||
let watcher = Arc::new(fs_watcher::FsWatcher::new(tx, pending_paths.clone()));
|
||||
|
||||
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.
|
||||
|
@ -731,7 +732,7 @@ impl Fs for RealFs {
|
|||
if let Some(parent) = path.parent() {
|
||||
target = parent.join(target);
|
||||
if let Ok(canonical) = self.canonicalize(&target).await {
|
||||
target = canonical;
|
||||
target = SanitizedPath::from(canonical).as_path().to_path_buf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -758,56 +759,6 @@ impl Fs for RealFs {
|
|||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
async fn watch(
|
||||
&self,
|
||||
path: &Path,
|
||||
_latency: Duration,
|
||||
) -> (
|
||||
Pin<Box<dyn Send + Stream<Item = Vec<PathEvent>>>>,
|
||||
Arc<dyn Watcher>,
|
||||
) {
|
||||
use notify::{EventKind, Watcher};
|
||||
|
||||
let (tx, rx) = smol::channel::unbounded();
|
||||
|
||||
let mut file_watcher = notify::recommended_watcher({
|
||||
let tx = tx.clone();
|
||||
move |event: Result<notify::Event, _>| {
|
||||
if let Some(event) = event.log_err() {
|
||||
let kind = match event.kind {
|
||||
EventKind::Create(_) => Some(PathEventKind::Created),
|
||||
EventKind::Modify(_) => Some(PathEventKind::Changed),
|
||||
EventKind::Remove(_) => Some(PathEventKind::Removed),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
tx.try_send(
|
||||
event
|
||||
.paths
|
||||
.into_iter()
|
||||
.map(|path| PathEvent { path, kind })
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
})
|
||||
.expect("Could not start file watcher");
|
||||
|
||||
file_watcher
|
||||
.watch(path, notify::RecursiveMode::Recursive)
|
||||
.log_err();
|
||||
|
||||
(
|
||||
Box::pin(rx.chain(futures::stream::once(async move {
|
||||
drop(file_watcher);
|
||||
vec![]
|
||||
}))),
|
||||
Arc::new(RealWatcher {}),
|
||||
)
|
||||
}
|
||||
|
||||
fn open_repo(&self, dotgit_path: &Path) -> Option<Arc<dyn GitRepository>> {
|
||||
// with libgit2, we can open git repo from an existing work dir
|
||||
// https://libgit2.org/docs/reference/main/repository/git_repository_open.html
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue