mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
358ce77581
commit
59eec67c35
13 changed files with 91 additions and 49 deletions
|
|
@ -71,8 +71,8 @@ macro_rules! emit {
|
|||
$crate::Event::Ctrl($exec, $layer).emit();
|
||||
};
|
||||
|
||||
(Cd($op:expr)) => {
|
||||
$crate::Event::Cd($op).emit();
|
||||
(Cd($url:expr)) => {
|
||||
$crate::Event::Cd($url).emit();
|
||||
};
|
||||
(Files($op:expr)) => {
|
||||
$crate::Event::Files($op).emit();
|
||||
|
|
|
|||
3
core/src/external/zoxide.rs
vendored
3
core/src/external/zoxide.rs
vendored
|
|
@ -17,12 +17,11 @@ pub fn zoxide(opt: ZoxideOpt) -> Result<Receiver<Result<Url>>> {
|
|||
.spawn()?;
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
let cwd = opt.cwd.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Ok(output) = child.wait_with_output().await {
|
||||
let selected = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
if !selected.is_empty() {
|
||||
tx.send(Ok(Url::new(selected, &cwd))).ok();
|
||||
tx.send(Ok(Url::from(selected))).ok();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,13 +46,12 @@ impl Files {
|
|||
let mut it = fs::read_dir(url).await?;
|
||||
let (tx, rx) = mpsc::unbounded_channel();
|
||||
|
||||
let url = url.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(Some(item)) = it.next_entry().await {
|
||||
select! {
|
||||
_ = tx.closed() => break,
|
||||
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 {
|
||||
match state {
|
||||
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();
|
||||
b
|
||||
}
|
||||
Some(false) => {
|
||||
if self.selected.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let b = self.items.iter().any(|f| self.selected.contains(&f.url));
|
||||
self.selected.clear();
|
||||
b
|
||||
}
|
||||
None => {
|
||||
for item in &self.items {
|
||||
|
|
@ -95,10 +107,10 @@ impl Files {
|
|||
self.selected.insert(item.url_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
!self.items.is_empty()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_index(&mut self, indices: &BTreeSet<usize>, state: Option<bool>) -> bool {
|
||||
let mut applied = false;
|
||||
|
|
@ -169,7 +181,7 @@ impl Files {
|
|||
}
|
||||
|
||||
#[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]
|
||||
pub fn duplicate(&self, idx: usize) -> Option<File> { self.items.get(idx).cloned() }
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@ pub enum FilesOp {
|
|||
|
||||
impl FilesOp {
|
||||
#[inline]
|
||||
pub fn url(&self) -> Url {
|
||||
pub fn url(&self) -> &Url {
|
||||
match self {
|
||||
Self::Full(url, _) => url,
|
||||
Self::Part(url, ..) => url,
|
||||
Self::Size(url, _) => url,
|
||||
Self::IOErr(url) => url,
|
||||
}
|
||||
.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ impl Input {
|
|||
};
|
||||
|
||||
snap.cursor = snap.count().saturating_sub(snap.mode.delta()).min(snap.cursor);
|
||||
if *snap == old {
|
||||
if snap == &old {
|
||||
return false;
|
||||
}
|
||||
if !matches!(old.op, InputOp::None | InputOp::Select(_)) {
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ impl Manager {
|
|||
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!(Refresh);
|
||||
}
|
||||
|
|
@ -326,7 +326,7 @@ impl Manager {
|
|||
}
|
||||
|
||||
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 hovered = self.hovered().map(|h| h.url_owned());
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ impl Manager {
|
|||
} else {
|
||||
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));
|
||||
|
|
@ -353,9 +353,9 @@ impl Manager {
|
|||
let url = op.url();
|
||||
let op = FilesOp::Full(url.clone(), Vec::new());
|
||||
|
||||
if url == *self.cwd() {
|
||||
if url == self.cwd() {
|
||||
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);
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ impl Preview {
|
|||
#[inline]
|
||||
pub fn same(&self, url: &Url, mime: &str) -> bool {
|
||||
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
|
||||
}
|
||||
|
|
@ -177,7 +177,7 @@ impl Preview {
|
|||
#[inline]
|
||||
pub fn same_mime(&self, url: &Url, mime: &str) -> bool {
|
||||
if let Some(ref lock) = self.lock {
|
||||
return lock.url == *url && lock.mime == mime;
|
||||
return &lock.url == url && lock.mime == mime;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
@ -185,7 +185,7 @@ impl Preview {
|
|||
#[inline]
|
||||
pub fn same_path(&self, url: &Url) -> bool {
|
||||
if let Some(ref lock) = self.lock {
|
||||
return lock.url == *url;
|
||||
return &lock.url == url;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ impl Tab {
|
|||
|
||||
let rep = self.history_new(&target);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ impl Tab {
|
|||
emit!(Input(InputOpt::top("Change directory:").with_value(target.to_string_lossy())));
|
||||
|
||||
if let Ok(s) = result.await {
|
||||
emit!(Cd(Url::new(s, &target)));
|
||||
emit!(Cd(Url::from(s)));
|
||||
}
|
||||
});
|
||||
false
|
||||
|
|
@ -143,7 +143,7 @@ impl Tab {
|
|||
|
||||
let rep = self.history_new(hovered.url());
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ impl Tab {
|
|||
|
||||
let rep = self.history_new(¤t);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -253,7 +253,12 @@ impl Tab {
|
|||
pin!(rx);
|
||||
|
||||
let version = FilesOp::prepare(&cwd);
|
||||
let mut first = true;
|
||||
while let Some(chunk) = rx.next().await {
|
||||
if first {
|
||||
emit!(Cd(cwd.clone()));
|
||||
first = false;
|
||||
}
|
||||
emit!(Files(FilesOp::Part(cwd.clone(), version, chunk)));
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -268,7 +273,7 @@ impl Tab {
|
|||
if self.current.cwd.is_search() {
|
||||
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));
|
||||
emit!(Refresh);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ impl Watcher {
|
|||
}
|
||||
|
||||
pub(super) fn watch(&mut self, mut watched: BTreeSet<&Url>) {
|
||||
watched.retain(|&u| u.is_regular());
|
||||
let (to_unwatch, to_watch): (BTreeSet<_>, BTreeSet<_>) = {
|
||||
let guard = self.watched.read();
|
||||
let keys = guard.keys().collect::<BTreeSet<_>>();
|
||||
|
|
@ -119,8 +120,12 @@ impl Watcher {
|
|||
}
|
||||
|
||||
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 dirs: Vec<_> = dirs.iter().map(|&u| u.clone()).collect();
|
||||
tokio::spawn(async move {
|
||||
for dir in dirs {
|
||||
Self::dir_changed(&dir, watched.clone()).await;
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ impl Tasks {
|
|||
pub fn file_cut(&self, src: &HashSet<Url>, dest: Url, force: bool) -> bool {
|
||||
for p in src {
|
||||
let to = dest.join(p.file_name().unwrap());
|
||||
if force && *p == to {
|
||||
if force && p == &to {
|
||||
trace!("file_cut: same file, skipping {:?}", to);
|
||||
} else {
|
||||
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 {
|
||||
for p in src {
|
||||
let to = dest.join(p.file_name().unwrap());
|
||||
if force && *p == to {
|
||||
if force && p == &to {
|
||||
trace!("file_copy: same file, skipping {:?}", to);
|
||||
} else {
|
||||
self.scheduler.file_copy(p.clone(), to, force, follow);
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ impl File {
|
|||
|
||||
let mut dirs = VecDeque::from([task.target]);
|
||||
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,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
|
@ -268,11 +268,11 @@ impl File {
|
|||
};
|
||||
|
||||
if meta.is_dir() {
|
||||
dirs.push_front(Url::new(entry.path(), &target));
|
||||
dirs.push_front(Url::from(entry.path()));
|
||||
continue;
|
||||
}
|
||||
|
||||
task.target = Url::new(entry.path(), &target);
|
||||
task.target = Url::from(entry.path());
|
||||
task.length = meta.len();
|
||||
self.sch.send(TaskOp::New(task.id, meta.len()))?;
|
||||
self.tx.send(FileOp::Delete(task.clone())).await?;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ impl Which {
|
|||
self.layer = layer;
|
||||
self.times = 1;
|
||||
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);
|
||||
true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ pub struct Url {
|
|||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub enum UrlScheme {
|
||||
#[default]
|
||||
None,
|
||||
Regular,
|
||||
Search,
|
||||
Archive,
|
||||
}
|
||||
|
|
@ -62,14 +62,26 @@ impl AsRef<OsStr> for Url {
|
|||
|
||||
impl Url {
|
||||
#[inline]
|
||||
pub fn new(url: impl Into<Url>, ctx: &Url) -> Self {
|
||||
let mut url: Self = url.into();
|
||||
url.scheme = ctx.scheme;
|
||||
url
|
||||
pub fn join(&self, path: impl AsRef<Path>) -> Self {
|
||||
let url = Self::from(self.path.join(path));
|
||||
match self.scheme {
|
||||
UrlScheme::Regular => url,
|
||||
UrlScheme::Search => url,
|
||||
UrlScheme::Archive => url.into_archive(),
|
||||
}
|
||||
}
|
||||
|
||||
#[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]
|
||||
pub fn strip_prefix(&self, base: impl AsRef<Path>) -> Option<&Path> {
|
||||
|
|
@ -83,32 +95,42 @@ impl Url {
|
|||
impl Url {
|
||||
// --- Scheme
|
||||
#[inline]
|
||||
pub fn is_none(&self) -> bool { self.scheme == UrlScheme::None }
|
||||
pub fn is_regular(&self) -> bool { self.scheme == UrlScheme::Regular }
|
||||
|
||||
#[inline]
|
||||
pub fn to_none(&self) -> Self {
|
||||
let mut url = self.clone();
|
||||
url.scheme = UrlScheme::None;
|
||||
url
|
||||
pub fn to_regular(&self) -> Self { self.clone().into_regular() }
|
||||
|
||||
#[inline]
|
||||
pub fn into_regular(mut self) -> Self {
|
||||
self.scheme = UrlScheme::Regular;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search }
|
||||
|
||||
#[inline]
|
||||
pub fn to_search(&self) -> Self {
|
||||
let mut url = self.clone();
|
||||
url.scheme = UrlScheme::Search;
|
||||
url
|
||||
pub fn to_search(&self) -> Self { self.clone().into_search() }
|
||||
|
||||
#[inline]
|
||||
pub fn into_search(mut self) -> Self {
|
||||
self.scheme = UrlScheme::Search;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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
|
||||
#[inline]
|
||||
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)) }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue