fix: directories are recreated after deletion did not update the watcher tracking properly (#381)

This commit is contained in:
三咲雅 · Misaki Masa 2023-11-21 00:50:26 +08:00 committed by GitHub
parent a6f76400f8
commit ac039c628e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 181 additions and 118 deletions

29
Cargo.lock generated
View file

@ -557,9 +557,9 @@ dependencies = [
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.6" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.48.0", "windows-sys 0.48.0",
@ -1576,9 +1576,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.21" version = "0.38.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
dependencies = [ dependencies = [
"bitflags 2.4.1", "bitflags 2.4.1",
"errno", "errno",
@ -2017,11 +2017,12 @@ dependencies = [
[[package]] [[package]]
name = "tracing-appender" name = "tracing-appender"
version = "0.2.2" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"thiserror",
"time", "time",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -2049,9 +2050,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.1.4" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
dependencies = [ dependencies = [
"log", "log",
"once_cell", "once_cell",
@ -2060,9 +2061,9 @@ dependencies = [
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.17" version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
dependencies = [ dependencies = [
"nu-ansi-term", "nu-ansi-term",
"sharded-slab", "sharded-slab",
@ -2608,18 +2609,18 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.25" version = "0.7.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557" checksum = "e97e415490559a91254a2979b4829267a57d2fcd741a98eee8b722fb57289aa0"
dependencies = [ dependencies = [
"zerocopy-derive", "zerocopy-derive",
] ]
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.7.25" version = "0.7.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b" checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -1,6 +1,6 @@
use yazi_config::keymap::{Exec, KeymapLayer}; use yazi_config::keymap::{Exec, KeymapLayer};
use crate::{completion::Completion, emit}; use crate::{completion::Completion, emit, input::Input};
pub struct Opt { pub struct Opt {
submit: bool, submit: bool,
@ -11,13 +11,15 @@ impl From<&Exec> for Opt {
} }
impl Completion { impl Completion {
#[inline]
pub fn _close() {
emit!(Call(Exec::call("close", vec![]).vec(), KeymapLayer::Completion));
}
pub fn close(&mut self, opt: impl Into<Opt>) -> bool { pub fn close(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if opt.submit { if opt.submit {
emit!(Call( Input::_complete(self.selected(), self.ticket);
Exec::call("complete", vec![self.selected().into()]).with("ticket", self.ticket).vec(),
KeymapLayer::Input
));
} }
self.caches.clear(); self.caches.clear();

View file

@ -6,14 +6,14 @@ use yazi_config::keymap::{Exec, KeymapLayer};
use crate::{completion::Completion, emit}; use crate::{completion::Completion, emit};
pub struct Opt<'a> { pub struct Opt<'a> {
before: &'a str, word: &'a str,
ticket: usize, ticket: usize,
} }
impl<'a> From<&'a Exec> for Opt<'a> { impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self { fn from(e: &'a Exec) -> Self {
Self { Self {
before: e.named.get("before").map(|s| s.as_str()).unwrap_or_default(), word: e.args.first().map(|s| s.as_str()).unwrap_or_default(),
ticket: e.named.get("ticket").and_then(|s| s.parse().ok()).unwrap_or(0), ticket: e.named.get("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
} }
} }
@ -21,11 +21,11 @@ impl<'a> From<&'a Exec> for Opt<'a> {
impl Completion { impl Completion {
#[inline] #[inline]
fn split_path(s: &str) -> (String, String) { pub fn _trigger(word: &str, ticket: usize) {
match s.rsplit_once(MAIN_SEPARATOR) { emit!(Call(
Some((p, c)) => (format!("{p}{}", MAIN_SEPARATOR), c.to_owned()), Exec::call("trigger", vec![word.to_owned()]).with("ticket", ticket).vec(),
None => (".".to_owned(), s.to_owned()), KeymapLayer::Completion
} ));
} }
pub fn trigger<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool { pub fn trigger<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool {
@ -35,7 +35,7 @@ impl Completion {
} }
self.ticket = opt.ticket; self.ticket = opt.ticket;
let (parent, child) = Self::split_path(opt.before); let (parent, child) = Self::split_path(opt.word);
if self.caches.contains_key(&parent) { if self.caches.contains_key(&parent) {
return self.show( return self.show(
@ -78,6 +78,14 @@ impl Completion {
mem::replace(&mut self.visible, false) mem::replace(&mut self.visible, false)
} }
#[inline]
fn split_path(s: &str) -> (String, String) {
match s.rsplit_once(MAIN_SEPARATOR) {
Some((p, c)) => (format!("{p}{}", MAIN_SEPARATOR), c.to_owned()),
None => (".".to_owned(), s.to_owned()),
}
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -21,11 +21,9 @@ pub enum Event {
Call(Vec<Exec>, KeymapLayer), Call(Vec<Exec>, KeymapLayer),
// Manager // Manager
Refresh,
Files(FilesOp), Files(FilesOp),
Pages(usize), Pages(usize),
Mimetype(BTreeMap<Url, String>), Mimetype(BTreeMap<Url, String>),
Hover(Option<Url>),
Peek(Option<(usize, Url)>), Peek(Option<(usize, Url)>),
Preview(PreviewLock), Preview(PreviewLock),
@ -82,12 +80,6 @@ macro_rules! emit {
(Mimetype($mimes:expr)) => { (Mimetype($mimes:expr)) => {
$crate::Event::Mimetype($mimes).emit(); $crate::Event::Mimetype($mimes).emit();
}; };
(Hover) => {
$crate::Event::Hover(None).emit();
};
(Hover($file:expr)) => {
$crate::Event::Hover(Some($file)).emit();
};
(Peek) => { (Peek) => {
$crate::Event::Peek(None).emit(); $crate::Event::Peek(None).emit();
}; };

View file

@ -1,7 +1,7 @@
use yazi_config::keymap::{Exec, KeymapLayer}; use yazi_config::keymap::Exec;
use yazi_shared::InputError; use yazi_shared::InputError;
use crate::{emit, input::Input}; use crate::{completion::Completion, input::Input};
pub struct Opt { pub struct Opt {
submit: bool, submit: bool,
@ -19,7 +19,7 @@ impl Input {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if self.completion { if self.completion {
emit!(Call(Exec::call("close", vec![]).vec(), KeymapLayer::Completion)); Completion::_close();
} }
if let Some(cb) = self.callback.take() { if let Some(cb) = self.callback.take() {

View file

@ -1,8 +1,8 @@
use std::path::MAIN_SEPARATOR; use std::path::MAIN_SEPARATOR;
use yazi_config::keymap::Exec; use yazi_config::keymap::{Exec, KeymapLayer};
use crate::input::Input; use crate::{emit, input::Input};
pub struct Opt<'a> { pub struct Opt<'a> {
word: &'a str, word: &'a str,
@ -19,6 +19,14 @@ impl<'a> From<&'a Exec> for Opt<'a> {
} }
impl Input { impl Input {
#[inline]
pub fn _complete(word: &str, ticket: usize) {
emit!(Call(
Exec::call("complete", vec![word.to_owned()]).with("ticket", ticket).vec(),
KeymapLayer::Input
));
}
pub fn complete<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool { pub fn complete<'a>(&mut self, opt: impl Into<Opt<'a>>) -> bool {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if self.ticket != opt.ticket { if self.ticket != opt.ticket {

View file

@ -1,6 +1,6 @@
use yazi_config::keymap::{Exec, KeymapLayer}; use yazi_config::keymap::Exec;
use crate::{emit, input::{op::InputOp, Input, InputMode}}; use crate::{completion::Completion, input::{op::InputOp, Input, InputMode}};
pub struct Opt; pub struct Opt;
@ -26,7 +26,7 @@ impl Input {
self.move_(-1); self.move_(-1);
if self.completion { if self.completion {
emit!(Call(Exec::call("close", vec![]).vec(), KeymapLayer::Completion)); Completion::_close();
} }
} }
} }

View file

@ -43,8 +43,8 @@ impl Manager {
Url::from(path.components().take(cwd.components().count() + 1).collect::<PathBuf>()); Url::from(path.components().take(cwd.components().count() + 1).collect::<PathBuf>());
if let Ok(f) = File::from(child.clone()).await { if let Ok(f) = File::from(child.clone()).await {
emit!(Files(FilesOp::Creating(cwd, f.into_map()))); emit!(Files(FilesOp::Creating(cwd, f.into_map())));
emit!(Hover(child)); Manager::_hover(Some(child));
emit!(Refresh); Manager::_refresh();
} }
Ok::<(), anyhow::Error>(()) Ok::<(), anyhow::Error>(())
}); });

View file

@ -0,0 +1,47 @@
use std::collections::BTreeSet;
use yazi_config::keymap::{Exec, KeymapLayer};
use yazi_shared::Url;
use crate::{emit, manager::Manager};
pub struct Opt {
url: Option<Url>,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { url: e.args.first().map(Url::from) } }
}
impl Manager {
#[inline]
pub fn _hover(url: Option<Url>) {
emit!(Call(
Exec::call("hover", url.map_or_else(Vec::new, |u| vec![u.to_string()])).vec(),
KeymapLayer::Manager
));
}
pub fn hover(&mut self, opt: impl Into<Opt>) -> bool {
// Refresh watcher
let mut to_watch = BTreeSet::new();
for tab in self.tabs.iter() {
to_watch.insert(&tab.current.cwd);
match tab.current.hovered() {
Some(h) if h.is_dir() => _ = to_watch.insert(&h.url),
_ => {}
}
if let Some(ref p) = tab.parent {
to_watch.insert(&p.cwd);
}
}
self.watcher.watch(to_watch);
// Trigger peek
emit!(Peek);
// Hover
let opt = opt.into() as Opt;
self.current_mut().repos(opt.url)
}
}

View file

@ -1,5 +1,6 @@
mod close; mod close;
mod create; mod create;
mod hover;
mod link; mod link;
mod open; mod open;
mod paste; mod paste;

View file

@ -1,10 +1,24 @@
use std::{collections::BTreeSet, env}; use std::env;
use yazi_config::keymap::{Exec, KeymapLayer};
use crate::{emit, manager::Manager}; use crate::{emit, manager::Manager};
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
}
impl Manager { impl Manager {
pub fn refresh(&mut self) { #[inline]
pub fn _refresh() {
emit!(Call(Exec::call("refresh", vec![]).vec(), KeymapLayer::Manager));
}
pub fn refresh(&mut self, _: impl Into<Opt>) -> bool {
env::set_current_dir(self.cwd()).ok(); env::set_current_dir(self.cwd()).ok();
env::set_var("PWD", self.cwd());
self.active_mut().apply_files_attrs(false); self.active_mut().apply_files_attrs(false);
@ -13,19 +27,8 @@ impl Manager {
} else { } else {
self.watcher.trigger_dirs(&[self.cwd()]); self.watcher.trigger_dirs(&[self.cwd()]);
} }
emit!(Hover);
let mut to_watch = BTreeSet::new(); Self::_hover(None);
for tab in self.tabs.iter() { false
to_watch.insert(&tab.current.cwd);
match tab.current.hovered() {
Some(h) if h.is_dir() => _ = to_watch.insert(&h.url),
_ => {}
}
if let Some(ref p) = tab.parent {
to_watch.insert(&p.cwd);
}
}
self.watcher.watch(to_watch);
} }
} }

View file

@ -27,7 +27,7 @@ impl Manager {
let file = File::from(new.clone()).await?; let file = File::from(new.clone()).await?;
emit!(Files(FilesOp::Creating(file.parent().unwrap(), file.into_map()))); emit!(Files(FilesOp::Creating(file.parent().unwrap(), file.into_map())));
emit!(Hover(new)); Self::_hover(Some(new));
Ok(()) Ok(())
} }

View file

@ -3,7 +3,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use yazi_shared::Url; use yazi_shared::Url;
use super::{Tabs, Watcher}; use super::{Tabs, Watcher};
use crate::{emit, files::{File, FilesOp}, tab::{Folder, Tab}, tasks::Tasks}; use crate::{files::{File, FilesOp}, tab::{Folder, Tab}, tasks::Tasks};
pub struct Manager { pub struct Manager {
pub tabs: Tabs, pub tabs: Tabs,
@ -46,7 +46,7 @@ impl Manager {
b |= hovered.as_ref().is_some_and(|h| self.current_mut().hover(h)); b |= hovered.as_ref().is_some_and(|h| self.current_mut().hover(h));
if hovered.as_ref() != self.hovered().map(|h| &h.url) { if hovered.as_ref() != self.hovered().map(|h| &h.url) {
emit!(Hover); Self::_hover(None);
} }
b b
} }

View file

@ -1,7 +1,7 @@
use yazi_config::BOOT; use yazi_config::BOOT;
use yazi_shared::Url; use yazi_shared::Url;
use crate::{emit, tab::Tab}; use crate::{manager::Manager, tab::Tab};
pub struct Tabs { pub struct Tabs {
pub idx: usize, pub idx: usize,
@ -32,7 +32,7 @@ impl Tabs {
pub(super) fn set_idx(&mut self, idx: usize) { pub(super) fn set_idx(&mut self, idx: usize) {
self.idx = idx; self.idx = idx;
self.active_mut().preview.reset(|l| l.is_image()); self.active_mut().preview.reset(|l| l.is_image());
emit!(Refresh); Manager::_refresh();
} }
} }

View file

@ -91,8 +91,8 @@ impl Watcher {
*guard = watched *guard = watched
.into_iter() .into_iter()
.map(|k| { .map(|k| {
if let Some((k, v)) = guard.remove_entry(k) { if let Some(old) = guard.remove_entry(k) {
(k, v) old
} else { } else {
to_resolve.push(k.clone()); to_resolve.push(k.clone());
(k.clone(), None) (k.clone(), None)
@ -102,17 +102,14 @@ impl Watcher {
let lock = self.watched.clone(); let lock = self.watched.clone();
tokio::spawn(async move { tokio::spawn(async move {
let mut ext = IndexMap::new();
for k in to_resolve { for k in to_resolve {
match fs::canonicalize(&k).await { match fs::canonicalize(&k).await {
Ok(v) if v != *k => { Ok(v) if v != *k => {
ext.insert(k, Some(Url::from(v))); lock.write().insert(k, Some(Url::from(v)));
} }
_ => {} _ => {}
} }
} }
lock.write().extend(ext);
}); });
} }

View file

@ -1,6 +1,6 @@
use yazi_config::keymap::Exec; use yazi_config::keymap::Exec;
use crate::{emit, tab::Tab, Step}; use crate::{manager::Manager, tab::Tab, Step};
pub struct Opt { pub struct Opt {
step: Step, step: Step,
@ -41,7 +41,7 @@ impl Tab {
} }
} }
emit!(Hover); Manager::_hover(None);
true true
} }
} }

View file

@ -5,7 +5,7 @@ use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::{keymap::{Exec, KeymapLayer}, popup::InputOpt}; use yazi_config::{keymap::{Exec, KeymapLayer}, popup::InputOpt};
use yazi_shared::{expand_path, Debounce, InputError, Url}; use yazi_shared::{expand_path, Debounce, InputError, Url};
use crate::{emit, tab::Tab}; use crate::{completion::Completion, emit, manager::Manager, tab::Tab};
pub struct Opt { pub struct Opt {
target: Url, target: Url,
@ -27,6 +27,11 @@ impl From<Url> for Opt {
} }
impl Tab { impl Tab {
#[inline]
pub fn _cd(target: &Url) {
emit!(Call(Exec::call("cd", vec![target.to_string()]).vec(), KeymapLayer::Manager));
}
pub fn cd(&mut self, opt: impl Into<Opt>) -> bool { pub fn cd(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if opt.interactive { if opt.interactive {
@ -59,7 +64,7 @@ impl Tab {
self.backstack.push(opt.target.clone()); self.backstack.push(opt.target.clone());
} }
emit!(Refresh); Manager::_refresh();
true true
} }
@ -75,24 +80,19 @@ impl Tab {
while let Some(result) = rx.next().await { while let Some(result) = rx.next().await {
match result { match result {
Ok(s) => { Ok(s) => {
let p = expand_path(s); let u = Url::from(expand_path(s));
let Ok(meta) = fs::metadata(&p).await else { let Ok(meta) = fs::metadata(&u).await else {
return; return;
}; };
emit!(Call( if meta.is_dir() {
Exec::call(if meta.is_dir() { "cd" } else { "reveal" }, vec![ Tab::_cd(&u);
p.to_string_lossy().to_string() } else {
]) Tab::_reveal(&u);
.vec(), }
KeymapLayer::Manager
));
} }
Err(InputError::Completed(before, ticket)) => { Err(InputError::Completed(before, ticket)) => {
emit!(Call( Completion::_trigger(&before, ticket);
Exec::call("complete", vec![]).with("before", before).with("ticket", ticket).vec(),
KeymapLayer::Input
));
} }
_ => break, _ => break,
} }

View file

@ -2,7 +2,7 @@ use std::mem;
use yazi_config::keymap::Exec; use yazi_config::keymap::Exec;
use crate::{emit, tab::Tab}; use crate::{manager::Manager, tab::Tab};
pub struct Opt; pub struct Opt;
impl From<()> for Opt { impl From<()> for Opt {
@ -34,7 +34,7 @@ impl Tab {
// Backstack // Backstack
self.backstack.push(hovered); self.backstack.push(hovered);
emit!(Refresh); Manager::_refresh();
true true
} }
} }

View file

@ -1,4 +1,4 @@
use yazi_config::keymap::{Exec, KeymapLayer}; use yazi_config::keymap::Exec;
use yazi_shared::{ends_with_slash, Defer}; use yazi_shared::{ends_with_slash, Defer};
use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, tab::Tab, Event, BLOCKER}; use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, tab::Tab, Event, BLOCKER};
@ -39,15 +39,21 @@ impl Tab {
let _defer = Defer::new(|| Event::Stop(false, None).emit()); let _defer = Defer::new(|| Event::Stop(false, None).emit());
emit!(Stop(true)).await; emit!(Stop(true)).await;
let url = if opt.type_ == OptType::Fzf { let result = if opt.type_ == OptType::Fzf {
external::fzf(FzfOpt { cwd }).await external::fzf(FzfOpt { cwd }).await
} else { } else {
external::zoxide(ZoxideOpt { cwd }).await external::zoxide(ZoxideOpt { cwd }).await
}?; };
let op = if opt.type_ == OptType::Fzf && !ends_with_slash(&url) { "reveal" } else { "cd" }; let Ok(url) = result else {
emit!(Call(Exec::call(op, vec![url.to_string()]).vec(), KeymapLayer::Manager)); return;
Ok::<(), anyhow::Error>(()) };
if opt.type_ == OptType::Fzf && !ends_with_slash(&url) {
Tab::_reveal(&url)
} else {
Tab::_cd(&url)
}
}); });
false false
} }

View file

@ -2,7 +2,7 @@ use std::mem;
use yazi_config::keymap::Exec; use yazi_config::keymap::Exec;
use crate::{emit, tab::Tab}; use crate::{manager::Manager, tab::Tab};
pub struct Opt; pub struct Opt;
impl From<()> for Opt { impl From<()> for Opt {
@ -43,7 +43,7 @@ impl Tab {
// Backstack // Backstack
self.backstack.push(current); self.backstack.push(current);
emit!(Refresh); Manager::_refresh();
true true
} }
} }

View file

@ -1,7 +1,7 @@
use yazi_config::keymap::Exec; use yazi_config::keymap::{Exec, KeymapLayer};
use yazi_shared::{expand_path, Url}; use yazi_shared::{expand_path, Url};
use crate::{emit, files::{File, FilesOp}, tab::Tab}; use crate::{emit, files::{File, FilesOp}, manager::Manager, tab::Tab};
pub struct Opt { pub struct Opt {
target: Url, target: Url,
@ -22,6 +22,11 @@ impl From<Url> for Opt {
} }
impl Tab { impl Tab {
#[inline]
pub fn _reveal(target: &Url) {
emit!(Call(Exec::call("reveal", vec![target.to_string()]).vec(), KeymapLayer::Manager));
}
pub fn reveal(&mut self, opt: impl Into<Opt>) -> bool { pub fn reveal(&mut self, opt: impl Into<Opt>) -> bool {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
@ -34,7 +39,7 @@ impl Tab {
parent.clone(), parent.clone(),
File::from_dummy(opt.target.clone()).into_map() File::from_dummy(opt.target.clone()).into_map()
))); )));
emit!(Hover(opt.target)); Manager::_hover(Some(opt.target));
b b
} }
} }

View file

@ -3,9 +3,9 @@ use std::{mem, time::Duration};
use anyhow::bail; use anyhow::bail;
use tokio::pin; use tokio::pin;
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::{keymap::{Exec, KeymapLayer}, popup::InputOpt}; use yazi_config::{keymap::Exec, popup::InputOpt};
use crate::{emit, external, files::FilesOp, tab::Tab}; use crate::{emit, external, files::FilesOp, manager::Manager, tab::Tab};
pub struct Opt { pub struct Opt {
pub type_: OptType, pub type_: OptType,
@ -61,7 +61,7 @@ impl Tab {
let mut first = true; let mut first = true;
while let Some(chunk) = rx.next().await { while let Some(chunk) = rx.next().await {
if first { if first {
emit!(Call(Exec::call("cd", vec![cwd.clone().to_string()]).vec(), KeymapLayer::Manager)); Tab::_cd(&cwd);
first = false; first = false;
} }
emit!(Files(FilesOp::Part(cwd.clone(), ticket, chunk))); emit!(Files(FilesOp::Part(cwd.clone(), ticket, chunk)));
@ -80,7 +80,7 @@ impl Tab {
let rep = self.history_new(&self.current.cwd.to_regular()); 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); Manager::_refresh();
} }
false false
} }

View file

@ -5,7 +5,7 @@ use crossterm::event::KeyEvent;
use ratatui::prelude::Rect; use ratatui::prelude::Rect;
use tokio::sync::oneshot; use tokio::sync::oneshot;
use yazi_config::{keymap::{Exec, Key, KeymapLayer}, BOOT}; use yazi_config::{keymap::{Exec, Key, KeymapLayer}, BOOT};
use yazi_core::{emit, files::FilesOp, input::InputMode, Ctx, Event}; use yazi_core::{emit, files::FilesOp, input::InputMode, manager::Manager, Ctx, Event};
use yazi_shared::Term; use yazi_shared::Term;
use crate::{Executor, Logs, Panic, Root, Signals}; use crate::{Executor, Logs, Panic, Root, Signals};
@ -110,7 +110,7 @@ impl App {
self.term = Some(Term::start().unwrap()); self.term = Some(Term::start().unwrap());
self.signals.stop_term(false); self.signals.stop_term(false);
emit!(Render); emit!(Render);
emit!(Hover); Manager::_hover(None);
} }
if let Some(tx) = tx { if let Some(tx) = tx {
tx.send(()).ok(); tx.send(()).ok();
@ -128,9 +128,6 @@ impl App {
let manager = &mut self.cx.manager; let manager = &mut self.cx.manager;
let tasks = &mut self.cx.tasks; let tasks = &mut self.cx.tasks;
match event { match event {
Event::Refresh => {
manager.refresh();
}
Event::Files(op) => { Event::Files(op) => {
let calc = !matches!(op, FilesOp::Size(..) | FilesOp::IOErr(_)); let calc = !matches!(op, FilesOp::Size(..) | FilesOp::IOErr(_));
let b = match op { let b = match op {
@ -154,12 +151,6 @@ impl App {
emit!(Peek); emit!(Peek);
} }
} }
Event::Hover(url) => {
if manager.current_mut().repos(url) {
emit!(Render);
}
emit!(Peek);
}
Event::Peek(sequent) => { Event::Peek(sequent) => {
if let Some((max, url)) = sequent { if let Some((max, url)) = sequent {
manager.active_mut().update_peek(max, url); manager.active_mut().update_peek(max, url);

View file

@ -88,10 +88,12 @@ impl<'a> Executor<'a> {
}; };
} }
on!(ACTIVE, escape); on!(MANAGER, hover);
on!(MANAGER, refresh);
on!(MANAGER, quit, &self.cx.tasks); on!(MANAGER, quit, &self.cx.tasks);
on!(MANAGER, close, &self.cx.tasks); on!(MANAGER, close, &self.cx.tasks);
on!(MANAGER, suspend); on!(MANAGER, suspend);
on!(ACTIVE, escape);
// Navigation // Navigation
on!(ACTIVE, arrow); on!(ACTIVE, arrow);
@ -212,7 +214,7 @@ impl<'a> Executor<'a> {
on!(move_, "move"); on!(move_, "move");
if exec.cmd.as_str() == "complete" { if exec.cmd.as_str() == "complete" {
return if exec.args.is_empty() { return if exec.named.contains_key("trigger") {
self.cx.completion.trigger(exec) self.cx.completion.trigger(exec)
} else { } else {
self.cx.input.complete(exec) self.cx.input.complete(exec)