This commit is contained in:
sxyazi 2023-09-06 22:53:07 +08:00
parent 358ce77581
commit 59eec67c35
No known key found for this signature in database
13 changed files with 91 additions and 49 deletions

View file

@ -71,8 +71,8 @@ macro_rules! emit {
$crate::Event::Ctrl($exec, $layer).emit(); $crate::Event::Ctrl($exec, $layer).emit();
}; };
(Cd($op:expr)) => { (Cd($url:expr)) => {
$crate::Event::Cd($op).emit(); $crate::Event::Cd($url).emit();
}; };
(Files($op:expr)) => { (Files($op:expr)) => {
$crate::Event::Files($op).emit(); $crate::Event::Files($op).emit();

View file

@ -17,12 +17,11 @@ pub fn zoxide(opt: ZoxideOpt) -> Result<Receiver<Result<Url>>> {
.spawn()?; .spawn()?;
let (tx, rx) = oneshot::channel(); let (tx, rx) = oneshot::channel();
let cwd = opt.cwd.clone();
tokio::spawn(async move { tokio::spawn(async move {
if let Ok(output) = child.wait_with_output().await { if let Ok(output) = child.wait_with_output().await {
let selected = String::from_utf8_lossy(&output.stdout).trim().to_string(); let selected = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !selected.is_empty() { if !selected.is_empty() {
tx.send(Ok(Url::new(selected, &cwd))).ok(); tx.send(Ok(Url::from(selected))).ok();
return; return;
} }
} }

View file

@ -46,13 +46,12 @@ impl Files {
let mut it = fs::read_dir(url).await?; let mut it = fs::read_dir(url).await?;
let (tx, rx) = mpsc::unbounded_channel(); let (tx, rx) = mpsc::unbounded_channel();
let url = url.clone();
tokio::spawn(async move { tokio::spawn(async move {
while let Ok(Some(item)) = it.next_entry().await { while let Ok(Some(item)) = it.next_entry().await {
select! { select! {
_ = tx.closed() => break, _ = tx.closed() => break,
Ok(meta) = item.metadata() => { Ok(meta) = item.metadata() => {
tx.send(File::from_meta(Url::new(item.path(), &url), meta).await).ok(); tx.send(File::from_meta(Url::from(item.path()), meta).await).ok();
} }
} }
} }
@ -82,10 +81,23 @@ impl Files {
pub fn select_all(&mut self, state: Option<bool>) -> bool { pub fn select_all(&mut self, state: Option<bool>) -> bool {
match state { match state {
Some(true) => { Some(true) => {
let b = if self.selected.len() < self.items.len() {
true
} else {
self.items.iter().any(|f| !self.selected.contains(&f.url))
};
self.selected = self.iter().map(|f| f.url_owned()).collect(); self.selected = self.iter().map(|f| f.url_owned()).collect();
b
} }
Some(false) => { Some(false) => {
if self.selected.is_empty() {
return false;
}
let b = self.items.iter().any(|f| self.selected.contains(&f.url));
self.selected.clear(); self.selected.clear();
b
} }
None => { None => {
for item in &self.items { for item in &self.items {
@ -95,10 +107,10 @@ impl Files {
self.selected.insert(item.url_owned()); self.selected.insert(item.url_owned());
} }
} }
}
}
!self.items.is_empty() !self.items.is_empty()
} }
}
}
pub fn select_index(&mut self, indices: &BTreeSet<usize>, state: Option<bool>) -> bool { pub fn select_index(&mut self, indices: &BTreeSet<usize>, state: Option<bool>) -> bool {
let mut applied = false; let mut applied = false;
@ -169,7 +181,7 @@ impl Files {
} }
#[inline] #[inline]
pub fn position(&self, url: &Url) -> Option<usize> { self.iter().position(|f| f.url == *url) } pub fn position(&self, url: &Url) -> Option<usize> { self.iter().position(|f| &f.url == url) }
#[inline] #[inline]
pub fn duplicate(&self, idx: usize) -> Option<File> { self.items.get(idx).cloned() } pub fn duplicate(&self, idx: usize) -> Option<File> { self.items.get(idx).cloned() }

View file

@ -17,14 +17,13 @@ pub enum FilesOp {
impl FilesOp { impl FilesOp {
#[inline] #[inline]
pub fn url(&self) -> Url { pub fn url(&self) -> &Url {
match self { match self {
Self::Full(url, _) => url, Self::Full(url, _) => url,
Self::Part(url, ..) => url, Self::Part(url, ..) => url,
Self::Size(url, _) => url, Self::Size(url, _) => url,
Self::IOErr(url) => url, Self::IOErr(url) => url,
} }
.clone()
} }
#[inline] #[inline]

View file

@ -308,7 +308,7 @@ impl Input {
}; };
snap.cursor = snap.count().saturating_sub(snap.mode.delta()).min(snap.cursor); snap.cursor = snap.count().saturating_sub(snap.mode.delta()).min(snap.cursor);
if *snap == old { if snap == &old {
return false; return false;
} }
if !matches!(old.op, InputOp::None | InputOp::Select(_)) { if !matches!(old.op, InputOp::None | InputOp::Select(_)) {

View file

@ -189,7 +189,7 @@ impl Manager {
fs::File::create(path).await?; fs::File::create(path).await?;
} }
if let Ok(file) = File::from(Url::new(hovered, &cwd)).await { if let Ok(file) = File::from(Url::from(hovered)).await {
emit!(Hover(file)); emit!(Hover(file));
emit!(Refresh); emit!(Refresh);
} }
@ -326,7 +326,7 @@ impl Manager {
} }
pub fn update_read(&mut self, op: FilesOp) -> bool { pub fn update_read(&mut self, op: FilesOp) -> bool {
let url = op.url(); let url = op.url().clone();
let cwd = self.cwd().to_owned(); let cwd = self.cwd().to_owned();
let hovered = self.hovered().map(|h| h.url_owned()); let hovered = self.hovered().map(|h| h.url_owned());
@ -337,7 +337,7 @@ impl Manager {
} else { } else {
self.active_mut().history.entry(url.clone()).or_insert_with(|| Folder::from(&url)).update(op); self.active_mut().history.entry(url.clone()).or_insert_with(|| Folder::from(&url)).update(op);
matches!(self.hovered(), Some(h) if *h.url() == url) matches!(self.hovered(), Some(h) if h.url() == &url)
}; };
b |= self.active_mut().parent.as_mut().map_or(false, |p| p.hover(&cwd)); b |= self.active_mut().parent.as_mut().map_or(false, |p| p.hover(&cwd));
@ -353,9 +353,9 @@ impl Manager {
let url = op.url(); let url = op.url();
let op = FilesOp::Full(url.clone(), Vec::new()); let op = FilesOp::Full(url.clone(), Vec::new());
if url == *self.cwd() { if url == self.cwd() {
self.current_mut().update(op); self.current_mut().update(op);
} else if matches!(self.parent(), Some(p) if p.cwd == url) { } else if matches!(self.parent(), Some(p) if &p.cwd == url) {
self.active_mut().parent.as_mut().unwrap().update(op); self.active_mut().parent.as_mut().unwrap().update(op);
} else { } else {
return false; return false;

View file

@ -169,7 +169,7 @@ impl Preview {
#[inline] #[inline]
pub fn same(&self, url: &Url, mime: &str) -> bool { pub fn same(&self, url: &Url, mime: &str) -> bool {
if let Some(ref lock) = self.lock { if let Some(ref lock) = self.lock {
return lock.url == *url && lock.mime == mime && lock.skip == self.skip; return &lock.url == url && lock.mime == mime && lock.skip == self.skip;
} }
false false
} }
@ -177,7 +177,7 @@ impl Preview {
#[inline] #[inline]
pub fn same_mime(&self, url: &Url, mime: &str) -> bool { pub fn same_mime(&self, url: &Url, mime: &str) -> bool {
if let Some(ref lock) = self.lock { if let Some(ref lock) = self.lock {
return lock.url == *url && lock.mime == mime; return &lock.url == url && lock.mime == mime;
} }
false false
} }
@ -185,7 +185,7 @@ impl Preview {
#[inline] #[inline]
pub fn same_path(&self, url: &Url) -> bool { pub fn same_path(&self, url: &Url) -> bool {
if let Some(ref lock) = self.lock { if let Some(ref lock) = self.lock {
return lock.url == *url; return &lock.url == url;
} }
false false
} }

View file

@ -106,7 +106,7 @@ impl Tab {
let rep = self.history_new(&target); let rep = self.history_new(&target);
let rep = mem::replace(&mut self.current, rep); let rep = mem::replace(&mut self.current, rep);
if !rep.cwd.is_search() { if rep.cwd.is_regular() {
self.history.insert(rep.cwd.clone(), rep); self.history.insert(rep.cwd.clone(), rep);
} }
@ -127,7 +127,7 @@ impl Tab {
emit!(Input(InputOpt::top("Change directory:").with_value(target.to_string_lossy()))); emit!(Input(InputOpt::top("Change directory:").with_value(target.to_string_lossy())));
if let Ok(s) = result.await { if let Ok(s) = result.await {
emit!(Cd(Url::new(s, &target))); emit!(Cd(Url::from(s)));
} }
}); });
false false
@ -143,7 +143,7 @@ impl Tab {
let rep = self.history_new(hovered.url()); let rep = self.history_new(hovered.url());
let rep = mem::replace(&mut self.current, rep); let rep = mem::replace(&mut self.current, rep);
if !rep.cwd.is_search() { if rep.cwd.is_regular() {
self.history.insert(rep.cwd.clone(), rep); self.history.insert(rep.cwd.clone(), rep);
} }
@ -178,7 +178,7 @@ impl Tab {
let rep = self.history_new(&current); let rep = self.history_new(&current);
let rep = mem::replace(&mut self.current, rep); let rep = mem::replace(&mut self.current, rep);
if !rep.cwd.is_search() { if rep.cwd.is_regular() {
self.history.insert(rep.cwd.clone(), rep); self.history.insert(rep.cwd.clone(), rep);
} }
@ -253,7 +253,12 @@ impl Tab {
pin!(rx); pin!(rx);
let version = FilesOp::prepare(&cwd); let version = FilesOp::prepare(&cwd);
let mut first = true;
while let Some(chunk) = rx.next().await { while let Some(chunk) = rx.next().await {
if first {
emit!(Cd(cwd.clone()));
first = false;
}
emit!(Files(FilesOp::Part(cwd.clone(), version, chunk))); emit!(Files(FilesOp::Part(cwd.clone(), version, chunk)));
} }
Ok(()) Ok(())
@ -268,7 +273,7 @@ impl Tab {
if self.current.cwd.is_search() { if self.current.cwd.is_search() {
self.preview_reset_image(); self.preview_reset_image();
let rep = self.history_new(&self.current.cwd.to_none()); let rep = self.history_new(&self.current.cwd.to_regular());
drop(mem::replace(&mut self.current, rep)); drop(mem::replace(&mut self.current, rep));
emit!(Refresh); emit!(Refresh);
} }

View file

@ -67,6 +67,7 @@ impl Watcher {
} }
pub(super) fn watch(&mut self, mut watched: BTreeSet<&Url>) { pub(super) fn watch(&mut self, mut watched: BTreeSet<&Url>) {
watched.retain(|&u| u.is_regular());
let (to_unwatch, to_watch): (BTreeSet<_>, BTreeSet<_>) = { let (to_unwatch, to_watch): (BTreeSet<_>, BTreeSet<_>) = {
let guard = self.watched.read(); let guard = self.watched.read();
let keys = guard.keys().collect::<BTreeSet<_>>(); let keys = guard.keys().collect::<BTreeSet<_>>();
@ -119,8 +120,12 @@ impl Watcher {
} }
pub(super) fn trigger_dirs(&self, dirs: &[&Url]) { pub(super) fn trigger_dirs(&self, dirs: &[&Url]) {
let dirs: Vec<_> = dirs.iter().filter(|&u| u.is_regular()).map(|&u| u.clone()).collect();
if dirs.is_empty() {
return;
}
let watched = self.watched.clone(); let watched = self.watched.clone();
let dirs: Vec<_> = dirs.iter().map(|&u| u.clone()).collect();
tokio::spawn(async move { tokio::spawn(async move {
for dir in dirs { for dir in dirs {
Self::dir_changed(&dir, watched.clone()).await; Self::dir_changed(&dir, watched.clone()).await;

View file

@ -157,7 +157,7 @@ impl Tasks {
pub fn file_cut(&self, src: &HashSet<Url>, dest: Url, force: bool) -> bool { pub fn file_cut(&self, src: &HashSet<Url>, dest: Url, force: bool) -> bool {
for p in src { for p in src {
let to = dest.join(p.file_name().unwrap()); let to = dest.join(p.file_name().unwrap());
if force && *p == to { if force && p == &to {
trace!("file_cut: same file, skipping {:?}", to); trace!("file_cut: same file, skipping {:?}", to);
} else { } else {
self.scheduler.file_cut(p.clone(), to, force); self.scheduler.file_cut(p.clone(), to, force);
@ -169,7 +169,7 @@ impl Tasks {
pub fn file_copy(&self, src: &HashSet<Url>, dest: Url, force: bool, follow: bool) -> bool { pub fn file_copy(&self, src: &HashSet<Url>, dest: Url, force: bool, follow: bool) -> bool {
for p in src { for p in src {
let to = dest.join(p.file_name().unwrap()); let to = dest.join(p.file_name().unwrap());
if force && *p == to { if force && p == &to {
trace!("file_copy: same file, skipping {:?}", to); trace!("file_copy: same file, skipping {:?}", to);
} else { } else {
self.scheduler.file_copy(p.clone(), to, force, follow); self.scheduler.file_copy(p.clone(), to, force, follow);

View file

@ -256,7 +256,7 @@ impl File {
let mut dirs = VecDeque::from([task.target]); let mut dirs = VecDeque::from([task.target]);
while let Some(target) = dirs.pop_front() { while let Some(target) = dirs.pop_front() {
let mut it = match fs::read_dir(&target).await { let mut it = match fs::read_dir(target).await {
Ok(it) => it, Ok(it) => it,
Err(_) => continue, Err(_) => continue,
}; };
@ -268,11 +268,11 @@ impl File {
}; };
if meta.is_dir() { if meta.is_dir() {
dirs.push_front(Url::new(entry.path(), &target)); dirs.push_front(Url::from(entry.path()));
continue; continue;
} }
task.target = Url::new(entry.path(), &target); task.target = Url::from(entry.path());
task.length = meta.len(); task.length = meta.len();
self.sch.send(TaskOp::New(task.id, meta.len()))?; self.sch.send(TaskOp::New(task.id, meta.len()))?;
self.tx.send(FileOp::Delete(task.clone())).await?; self.tx.send(FileOp::Delete(task.clone())).await?;

View file

@ -23,7 +23,7 @@ impl Which {
self.layer = layer; self.layer = layer;
self.times = 1; self.times = 1;
self.cands = self.cands =
KEYMAP.get(layer).iter().filter(|s| s.on.len() > 1 && s.on[0] == *key).cloned().collect(); KEYMAP.get(layer).iter().filter(|s| s.on.len() > 1 && &s.on[0] == key).cloned().collect();
self.switch(true); self.switch(true);
true true
} }

View file

@ -9,7 +9,7 @@ pub struct Url {
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum UrlScheme { pub enum UrlScheme {
#[default] #[default]
None, Regular,
Search, Search,
Archive, Archive,
} }
@ -62,14 +62,26 @@ impl AsRef<OsStr> for Url {
impl Url { impl Url {
#[inline] #[inline]
pub fn new(url: impl Into<Url>, ctx: &Url) -> Self { pub fn join(&self, path: impl AsRef<Path>) -> Self {
let mut url: Self = url.into(); let url = Self::from(self.path.join(path));
url.scheme = ctx.scheme; match self.scheme {
url UrlScheme::Regular => url,
UrlScheme::Search => url,
UrlScheme::Archive => url.into_archive(),
}
} }
#[inline] #[inline]
pub fn join(&self, path: impl AsRef<Path>) -> Self { Self::new(self.path.join(path), self) } pub fn parent_url(&self) -> Option<Url> {
self.path.parent().map(|p| {
let url = Self::from(p);
match self.scheme {
UrlScheme::Regular => url,
UrlScheme::Search => url,
UrlScheme::Archive => url,
}
})
}
#[inline] #[inline]
pub fn strip_prefix(&self, base: impl AsRef<Path>) -> Option<&Path> { pub fn strip_prefix(&self, base: impl AsRef<Path>) -> Option<&Path> {
@ -83,32 +95,42 @@ impl Url {
impl Url { impl Url {
// --- Scheme // --- Scheme
#[inline] #[inline]
pub fn is_none(&self) -> bool { self.scheme == UrlScheme::None } pub fn is_regular(&self) -> bool { self.scheme == UrlScheme::Regular }
#[inline] #[inline]
pub fn to_none(&self) -> Self { pub fn to_regular(&self) -> Self { self.clone().into_regular() }
let mut url = self.clone();
url.scheme = UrlScheme::None; #[inline]
url pub fn into_regular(mut self) -> Self {
self.scheme = UrlScheme::Regular;
self
} }
#[inline] #[inline]
pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search } pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search }
#[inline] #[inline]
pub fn to_search(&self) -> Self { pub fn to_search(&self) -> Self { self.clone().into_search() }
let mut url = self.clone();
url.scheme = UrlScheme::Search; #[inline]
url pub fn into_search(mut self) -> Self {
self.scheme = UrlScheme::Search;
self
} }
#[inline] #[inline]
pub fn is_archive(&self) -> bool { self.scheme == UrlScheme::Archive } pub fn is_archive(&self) -> bool { self.scheme == UrlScheme::Archive }
#[inline]
pub fn to_archive(&self) -> Self { self.clone().into_archive() }
#[inline]
pub fn into_archive(mut self) -> Self {
self.scheme = UrlScheme::Archive;
self
}
// --- Path // --- Path
#[inline] #[inline]
pub fn set_path(&mut self, path: PathBuf) { self.path = path; } pub fn set_path(&mut self, path: PathBuf) { self.path = path; }
#[inline]
pub fn parent_url(&self) -> Option<Url> { self.path.parent().map(|p| Self::new(p, self)) }
} }