mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat: auto fallback to parents of the folder that no longer exists
This commit is contained in:
parent
7071177bcd
commit
becf62417a
8 changed files with 76 additions and 29 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue