feat: auto fallback to parents of the folder that no longer exists

This commit is contained in:
sxyazi 2023-07-11 15:56:57 +08:00
parent 7071177bcd
commit becf62417a
No known key found for this signature in database
8 changed files with 76 additions and 29 deletions

View file

@ -3,7 +3,7 @@ use std::{fs::Metadata, path::{Path, PathBuf}};
use anyhow::Result;
use tokio::fs;
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct File {
pub name: String,
pub path: PathBuf,

View file

@ -1,10 +1,11 @@
use std::{ops::{Deref, DerefMut}, path::{Path, PathBuf}};
use anyhow::Result;
use indexmap::IndexMap;
use tokio::fs;
use super::File;
use crate::{config::{manager::SortBy, MANAGER}, emit};
use crate::config::{manager::SortBy, MANAGER};
#[derive(Default)]
pub struct Files {
@ -14,7 +15,7 @@ pub struct Files {
}
impl Files {
pub async fn from(paths: Vec<PathBuf>) -> IndexMap<PathBuf, File> {
pub async fn read(paths: Vec<PathBuf>) -> IndexMap<PathBuf, File> {
let mut items = IndexMap::new();
for path in paths {
if let Ok(file) = File::from(&path).await {
@ -24,21 +25,17 @@ impl Files {
items
}
pub async fn read(path: &Path) {
let mut iter = match fs::read_dir(path).await {
Ok(it) => it,
Err(_) => return,
};
pub async fn read_dir(path: &Path) -> Result<IndexMap<PathBuf, File>> {
let mut it = fs::read_dir(path).await?;
let mut items = IndexMap::new();
while let Ok(Some(item)) = iter.next_entry().await {
while let Ok(Some(item)) = it.next_entry().await {
if let Ok(meta) = item.metadata().await {
let path = item.path();
let file = File::from_meta(&path, meta).await;
items.insert(path, file);
}
}
emit!(Files(FilesOp::Read(path.to_path_buf(), items)));
Ok(items)
}
pub fn sort(&mut self) {
@ -121,6 +118,7 @@ impl Default for FilesSort {
pub enum FilesOp {
Read(PathBuf, IndexMap<PathBuf, File>),
IOErr(PathBuf),
Search(PathBuf, IndexMap<PathBuf, File>),
}
@ -129,8 +127,12 @@ impl FilesOp {
pub fn path(&self) -> PathBuf {
match self {
Self::Read(path, _) => path,
Self::IOErr(path) => path,
Self::Search(path, _) => path,
}
.clone()
}
#[inline]
pub fn read_empty(path: &Path) -> Self { Self::Read(path.to_path_buf(), IndexMap::new()) }
}

View file

@ -27,6 +27,7 @@ impl Folder {
let b = match op {
FilesOp::Read(_, items) => self.files.update_read(items),
FilesOp::Search(_, items) => self.files.update_search(items),
_ => unreachable!(),
};
if !b {
return false;

View file

@ -38,7 +38,9 @@ impl Manager {
to_watch.insert(p.cwd.clone());
}
if let Some(ref h) = tab.current.hovered() {
to_watch.insert(h.path.clone());
if h.meta.is_dir() {
to_watch.insert(h.path.clone());
}
}
}
self.watcher.watch(to_watch);
@ -169,8 +171,8 @@ impl Manager {
pub fn update_read(&mut self, op: FilesOp) -> bool {
let path = op.path();
let cwd = self.current().cwd.clone();
let hovered = self.hovered().map(|h| h.path.clone());
let mut b = if cwd == path && !self.current().in_search {
self.current_mut().update(op)
} else if matches!(self.parent(), Some(p) if p.cwd == path) {
@ -195,6 +197,22 @@ impl Manager {
b
}
pub fn update_ioerr(&mut self, op: FilesOp) -> bool {
let path = op.path();
let op = FilesOp::read_empty(&path);
if path == self.current().cwd {
self.current_mut().update(op);
} else if matches!(self.parent(), Some(p) if p.cwd == path) {
self.active_mut().parent.as_mut().unwrap().update(op);
} else {
return false;
}
self.active_mut().leave();
true
}
pub fn update_search(&mut self, op: FilesOp) -> bool {
let path = op.path();
if !self.current().in_search || self.current().cwd != path {

View file

@ -6,7 +6,7 @@ use syntect::{easy::HighlightLines, highlighting::{Theme, ThemeSet}, parsing::Sy
use tokio::{fs, task::JoinHandle};
use super::{ALL_RATIO, PREVIEW_BORDER, PREVIEW_PADDING, PREVIEW_RATIO};
use crate::{config::{PREVIEW, THEME}, core::{adapter::Kitty, files::Files, tasks::Precache}, emit, misc::{first_n_lines, tty_ratio, tty_size}};
use crate::{config::{PREVIEW, THEME}, core::{adapter::Kitty, files::{Files, FilesOp}, tasks::Precache}, emit, misc::{first_n_lines, tty_ratio, tty_size}};
static SYNTECT_SYNTAX: OnceLock<SyntaxSet> = OnceLock::new();
static SYNTECT_THEME: OnceLock<Theme> = OnceLock::new();
@ -74,7 +74,11 @@ impl Preview {
}
pub async fn folder(path: &Path) -> Result<PreviewData> {
Files::read(&path).await;
emit!(Files(match Files::read_dir(&path).await {
Ok(items) => FilesOp::Read(path.to_path_buf(), items),
Err(_) => FilesOp::IOErr(path.to_path_buf()),
}));
Ok(PreviewData::Folder)
}

View file

@ -158,7 +158,7 @@ impl Tab {
if chunk.is_empty() {
break;
}
emit!(Files(FilesOp::Search(cwd.clone(), Files::from(chunk).await)));
emit!(Files(FilesOp::Search(cwd.clone(), Files::read(chunk).await)));
}
Ok(())
}));

View file

@ -1,9 +1,9 @@
use std::{collections::BTreeSet, path::{Path, PathBuf}};
use notify::{RecommendedWatcher, Watcher as _Watcher};
use notify::{event::{MetadataKind, ModifyKind}, EventKind, RecommendedWatcher, Watcher as _Watcher};
use tokio::sync::mpsc::{self, Sender};
use crate::core::files::Files;
use crate::{core::files::{Files, FilesOp}, emit};
pub struct Watcher {
tx: Sender<PathBuf>,
@ -31,20 +31,38 @@ impl Watcher {
}
let event = res.unwrap();
match event.kind {
notify::EventKind::Create(_) => {}
notify::EventKind::Modify(_) => {}
notify::EventKind::Remove(_) => {}
_ => return,
}
let path = if event.paths.len() > 0 {
event.paths[0].parent().unwrap_or(&event.paths[0])
let path = if let Some(first) = event.paths.first() {
first.clone()
} else {
return;
};
tx.blocking_send(path.to_path_buf()).ok();
let parent = path.parent().unwrap_or(&path).to_path_buf();
match event.kind {
EventKind::Create(_) => {
tx.blocking_send(parent).ok();
}
EventKind::Modify(kind) => {
match kind {
ModifyKind::Metadata(kind) => match kind {
MetadataKind::Permissions => {}
MetadataKind::Ownership => {}
MetadataKind::Extended => {}
_ => return,
},
ModifyKind::Name(_) => {}
_ => return,
};
tx.blocking_send(path).ok();
tx.blocking_send(parent).ok();
}
EventKind::Remove(_) => {
tx.blocking_send(path).ok();
tx.blocking_send(parent).ok();
}
_ => return,
}
}
},
notify::Config::default(),
@ -53,7 +71,10 @@ impl Watcher {
tokio::spawn(async move {
while let Some(path) = rx.recv().await {
Files::read(&path).await;
emit!(Files(match Files::read_dir(&path).await {
Ok(items) => FilesOp::Read(path, items),
Err(_) => FilesOp::IOErr(path),
}));
}
});

View file

@ -77,6 +77,7 @@ impl App {
Event::Files(op) => {
let b = match op {
FilesOp::Read(..) => manager.update_read(op),
FilesOp::IOErr(..) => manager.update_ioerr(op),
FilesOp::Search(..) => manager.update_search(op),
};
if b {