From 2771aef677305b9bbaab16dda78ab666744770c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Wed, 4 Dec 2024 22:44:35 +0800 Subject: [PATCH] fix: propagate and update the directory node till its first parent when the files of a directory change (#1987) --- .../src/manager/commands/update_files.rs | 8 ++---- yazi-core/src/manager/linked.rs | 20 +++++++------- yazi-core/src/manager/watcher.rs | 26 +++++++++++++------ yazi-plugin/preset/ya.lua | 7 +++-- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/yazi-core/src/manager/commands/update_files.rs b/yazi-core/src/manager/commands/update_files.rs index 9f4451f18..9498f7f33 100644 --- a/yazi-core/src/manager/commands/update_files.rs +++ b/yazi-core/src/manager/commands/update_files.rs @@ -25,12 +25,8 @@ impl Manager { return; }; - let mut ops = vec![opt.op]; - for u in LINKED.read().from_dir(ops[0].cwd()) { - ops.push(ops[0].rebase(u)); - } - - for op in ops { + let linked: Vec<_> = LINKED.read().from_dir(opt.op.cwd()).map(|u| opt.op.rebase(u)).collect(); + for op in [opt.op].into_iter().chain(linked) { let idx = self.tabs.cursor; self.yanked.apply_op(&op); diff --git a/yazi-core/src/manager/linked.rs b/yazi-core/src/manager/linked.rs index 2de344d27..88fb4e519 100644 --- a/yazi-core/src/manager/linked.rs +++ b/yazi-core/src/manager/linked.rs @@ -16,29 +16,27 @@ impl DerefMut for Linked { } impl Linked { - pub fn from_dir(&self, url: &Url) -> Vec<&Url> { + pub fn from_dir<'a, 'b>(&'a self, url: &'b Url) -> Box + 'b> + where + 'a: 'b, + { if let Some(to) = self.get(url) { - self.iter().filter(|(k, v)| *v == to && *k != url).map(|(k, _)| k).collect() + Box::new(self.iter().filter(move |(k, v)| *v == to && *k != url).map(|(k, _)| k)) } else { - self.iter().filter(|(_, v)| *v == url).map(|(k, _)| k).collect() + Box::new(self.iter().filter(move |(_, v)| *v == url).map(|(k, _)| k)) } } pub fn from_file(&self, url: &Url) -> Vec { if self.is_empty() { - return Default::default(); + return vec![]; } let Some(p) = url.parent_url() else { - return Default::default(); + return vec![]; }; - let relatives = self.from_dir(&p); - if relatives.is_empty() { - return Default::default(); - } - let name = url.file_name().unwrap(); - relatives.into_iter().map(|u| u.join(name)).collect() + self.from_dir(&p).map(|u| u.join(name)).collect() } } diff --git a/yazi-core/src/manager/watcher.rs b/yazi-core/src/manager/watcher.rs index abab62642..68697fcf9 100644 --- a/yazi-core/src/manager/watcher.rs +++ b/yazi-core/src/manager/watcher.rs @@ -34,9 +34,7 @@ impl Watcher { if event.kind.is_access() { return; } - for path in event.paths { - out_tx_.send(Url::from(path)).ok(); - } + Self::push_files_impl(&out_tx_, event.paths.into_iter().map(Url::from)); }; let config = notify::Config::default().with_poll_interval(Duration::from_millis(500)); @@ -55,11 +53,23 @@ impl Watcher { self.in_tx.send(new.into_iter().cloned().collect()).ok(); } - pub(super) fn push_files(&self, url: Vec) { - let watched = WATCHED.read(); - for u in url { - if u.parent_url().is_some_and(|p| watched.contains(&p)) { - self.out_tx.send(u).ok(); + pub(super) fn push_files(&self, urls: Vec) { + Self::push_files_impl(&self.out_tx, urls.into_iter()); + } + + fn push_files_impl(out_tx: &mpsc::UnboundedSender, urls: impl Iterator) { + let (mut parents, watched) = (HashSet::new(), WATCHED.read()); + for u in urls { + let Some(p) = u.parent_url() else { continue }; + if !watched.contains(&p) + && LINKED.read().from_dir(&p).find(|&u| watched.contains(u)).is_none() + { + continue; + } + out_tx.send(u).ok(); + if !parents.contains(&p) { + out_tx.send(p.clone()).ok(); + parents.insert(p); } } } diff --git a/yazi-plugin/preset/ya.lua b/yazi-plugin/preset/ya.lua index a8a935a1d..da504d5ae 100644 --- a/yazi-plugin/preset/ya.lua +++ b/yazi-plugin/preset/ya.lua @@ -1,4 +1,3 @@ -table.unpack = table.unpack or unpack function Err(s, ...) return Error.custom(string.format(s, ...)) end function ya.clamp(min, x, max) @@ -30,11 +29,11 @@ end function ya.readable_size(size) local units = { "B", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q" } local i = 1 - while size > 1024.0 and i < #units do - size = size / 1024.0 + while size > 1024 and i < #units do + size = size / 1024 i = i + 1 end - return string.format("%.1f%s", size, units[i]) + return string.format("%.1f%s", size, units[i]):gsub("[.,]0", "", 1) end function ya.readable_path(path)