feat: add file/folder differentiation to the cd command to support revealing directory

This commit is contained in:
sxyazi 2023-11-06 08:23:02 +08:00
parent 1f744810f4
commit e7e75b8365
No known key found for this signature in database

View file

@ -62,7 +62,7 @@ impl Watcher {
); );
let instance = Self { watcher: watcher.unwrap(), watched: Default::default() }; let instance = Self { watcher: watcher.unwrap(), watched: Default::default() };
tokio::spawn(Self::changed(rx, instance.watched.clone())); tokio::spawn(Self::on_changed(rx, instance.watched.clone()));
instance instance
} }
@ -124,13 +124,17 @@ impl Watcher {
let watched = self.watched.clone(); let watched = self.watched.clone();
tokio::spawn(async move { tokio::spawn(async move {
let watched = watched.read().clone();
for dir in dirs { for dir in dirs {
Self::dir_changed(&dir, watched.clone()).await; Self::dir_changed(&dir, &watched).await;
} }
}); });
} }
async fn changed(rx: UnboundedReceiver<Url>, watched: Arc<RwLock<IndexMap<Url, Option<Url>>>>) { async fn on_changed(
rx: UnboundedReceiver<Url>,
watched: Arc<RwLock<IndexMap<Url, Option<Url>>>>,
) {
// TODO: revert this once a new notification is implemented // TODO: revert this once a new notification is implemented
// let rx = UnboundedReceiverStream::new(rx).chunks_timeout(100, // let rx = UnboundedReceiverStream::new(rx).chunks_timeout(100,
// Duration::from_millis(200)); // Duration::from_millis(200));
@ -147,70 +151,76 @@ impl Watcher {
} }
} }
Self::file_changed(&files, watched.clone()).await; let watched = watched.read().clone();
Self::files_changed(&files, &watched).await;
for file in files { for file in files {
for u in Self::linked_urls(&file, &watched) {
emit!(Files(FilesOp::IOErr(u.clone())));
}
emit!(Files(FilesOp::IOErr(file))); emit!(Files(FilesOp::IOErr(file)));
} }
for dir in dirs { for dir in dirs {
Self::dir_changed(&dir, watched.clone()).await; Self::dir_changed(&dir, &watched).await;
} }
} }
} }
async fn file_changed(urls: &[Url], watched: Arc<RwLock<IndexMap<Url, Option<Url>>>>) { async fn files_changed(urls: &[Url], watched: &IndexMap<Url, Option<Url>>) {
let Ok(mut mimes) = external::file(urls).await else { let Ok(mut mimes) = external::file(urls).await else {
return; return;
}; };
let linked: Vec<_> = watched let linked: Vec<_> = watched.iter().filter_map(|(k, v)| v.as_ref().map(|v| (k, v))).fold(
.read() Vec::new(),
.iter() |mut aac, (k, v)| {
.filter_map(|(k, v)| v.as_ref().map(|v| (k, v)))
.fold(Vec::new(), |mut aac, (k, v)| {
mimes mimes
.iter() .iter()
.filter(|(f, _)| f.parent().map(|p| p == **v) == Some(true)) .filter(|(u, _)| u.parent().map(|p| p == **v) == Some(true))
.for_each(|(f, m)| aac.push((k.join(f.file_name().unwrap()), m.clone()))); .for_each(|(u, m)| aac.push((k.join(u.file_name().unwrap()), m.clone())));
aac aac
}); },
);
mimes.extend(linked); mimes.extend(linked);
emit!(Mimetype(mimes)); emit!(Mimetype(mimes));
} }
async fn dir_changed(url: &Url, watched: Arc<RwLock<IndexMap<Url, Option<Url>>>>) { async fn dir_changed(url: &Url, watched: &IndexMap<Url, Option<Url>>) {
let linked: Vec<_> = watched let linked = Self::linked_urls(url, watched);
.read()
.iter()
.filter_map(|(k, v)| v.as_ref().map(|v| (k, v)))
.filter(|(_, v)| *v == url)
.map(|(k, _)| k.clone())
.collect();
let Ok(rx) = Files::from_dir(url).await else { let Ok(rx) = Files::from_dir(url).await else {
emit!(Files(FilesOp::IOErr(url.clone()))); emit!(Files(FilesOp::IOErr(url.clone())));
for ori in linked { for u in linked {
emit!(Files(FilesOp::IOErr(ori))); emit!(Files(FilesOp::IOErr(u.clone())));
} }
return; return;
}; };
let linked_files = |files: &[File], ori: &Url| -> Vec<File> { let linked_files = |files: &[File], linked: &Url| -> Vec<File> {
let mut new = Vec::with_capacity(files.len()); let mut new = Vec::with_capacity(files.len());
for file in files { for file in files {
let mut file = file.clone(); let mut file = file.clone();
file.url = ori.join(file.url.strip_prefix(url).unwrap()); file.url = linked.join(file.url.strip_prefix(url).unwrap());
new.push(file); new.push(file);
} }
new new
}; };
let files: Vec<_> = UnboundedReceiverStream::new(rx).collect().await; let files: Vec<_> = UnboundedReceiverStream::new(rx).collect().await;
for ori in linked { for u in linked {
let files = linked_files(&files, &ori); let files = linked_files(&files, u);
emit!(Files(FilesOp::Full(ori, files))); emit!(Files(FilesOp::Full(u.clone(), files)));
} }
emit!(Files(FilesOp::Full(url.clone(), files))); emit!(Files(FilesOp::Full(url.clone(), files)));
} }
fn linked_urls<'a>(url: &'a Url, watched: &'a IndexMap<Url, Option<Url>>) -> Vec<&'a Url> {
watched
.iter()
.filter_map(|(k, v)| v.as_ref().map(|v| (k, v)))
.filter(|(_, v)| *v == url)
.map(|(k, _)| k)
.collect()
}
} }