From ff369f4d1561d0ab4d3acb7dccb198cc03fd2f3c Mon Sep 17 00:00:00 2001 From: sxyazi Date: Wed, 22 Nov 2023 11:43:30 +0800 Subject: [PATCH] .. --- yazi-core/src/event.rs | 7 -- yazi-core/src/help/help.rs | 5 +- yazi-core/src/manager/commands/hover.rs | 15 ++- yazi-core/src/manager/commands/peek.rs | 80 ++++++++++++--- yazi-core/src/preview/preview.rs | 129 +++++------------------- yazi-core/src/tab/commands/hidden.rs | 4 +- yazi-core/src/tab/tab.rs | 12 --- yazi-core/src/tasks/commands/toggle.rs | 5 +- yazi-core/src/which/which.rs | 3 +- yazi-fm/src/app.rs | 13 +-- yazi-fm/src/executor.rs | 6 +- yazi-plugin/src/components/preview.rs | 10 +- 12 files changed, 118 insertions(+), 171 deletions(-) diff --git a/yazi-core/src/event.rs b/yazi-core/src/event.rs index f0544455..485f7972 100644 --- a/yazi-core/src/event.rs +++ b/yazi-core/src/event.rs @@ -24,7 +24,6 @@ pub enum Event { Files(FilesOp), Pages(usize), Mimetype(BTreeMap), - Peek(Option<(usize, Url)>), Preview(PreviewLock), // Input @@ -80,12 +79,6 @@ macro_rules! emit { (Mimetype($mimes:expr)) => { $crate::Event::Mimetype($mimes).emit(); }; - (Peek) => { - $crate::Event::Peek(None).emit(); - }; - (Peek($skip:expr, $url:expr)) => { - $crate::Event::Peek(Some(($skip, $url))).emit(); - }; (Preview($lock:expr)) => { $crate::Event::Preview($lock).emit(); }; diff --git a/yazi-core/src/help/help.rs b/yazi-core/src/help/help.rs index a50f8641..94e9734f 100644 --- a/yazi-core/src/help/help.rs +++ b/yazi-core/src/help/help.rs @@ -4,7 +4,7 @@ use yazi_config::{keymap::{Control, Key, KeymapLayer}, KEYMAP}; use yazi_shared::Term; use super::HELP_MARGIN; -use crate::{emit, input::Input}; +use crate::input::Input; #[derive(Default)] pub struct Help { @@ -35,7 +35,8 @@ impl Help { self.offset = 0; self.cursor = 0; - emit!(Peek); // Show/hide preview for images + // TODO: Peek + // emit!(Peek); // Show/hide preview for images true } diff --git a/yazi-core/src/manager/commands/hover.rs b/yazi-core/src/manager/commands/hover.rs index 78e1311d..617bf615 100644 --- a/yazi-core/src/manager/commands/hover.rs +++ b/yazi-core/src/manager/commands/hover.rs @@ -23,24 +23,23 @@ impl Manager { } pub fn hover(&mut self, opt: impl Into) -> bool { + // Re-peek + self.peek(0); + // 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); } + if let Some(h) = tab.current.hovered().filter(|&h| h.is_dir()) { + to_watch.insert(&h.url); + } } self.watcher.watch(to_watch); - // Trigger peek - emit!(Peek); - - // Hover + // Hover on the file let opt = opt.into() as Opt; self.current_mut().repos(opt.url) } diff --git a/yazi-core/src/manager/commands/peek.rs b/yazi-core/src/manager/commands/peek.rs index 708a0f4c..4a95253a 100644 --- a/yazi-core/src/manager/commands/peek.rs +++ b/yazi-core/src/manager/commands/peek.rs @@ -1,27 +1,83 @@ -use crate::manager::Manager; +use yazi_config::{keymap::{Exec, KeymapLayer}, MANAGER}; +use yazi_shared::{Url, MIME_DIR}; + +use crate::{emit, manager::Manager}; + +pub struct Opt { + step: isize, + sequent: Option, + upper_bound: Option, +} + +impl From<&Exec> for Opt { + fn from(e: &Exec) -> Self { + Self { + step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0), + sequent: e.named.get("sequent").map(Url::from), + upper_bound: e.named.get("upper-bound").and_then(|s| s.parse().ok()), + } + } +} +impl From for Opt { + fn from(step: isize) -> Self { Self { step, sequent: None, upper_bound: None } } +} impl Manager { - pub fn peek(&mut self, sequent: bool) -> bool { - let Some(hovered) = self.hovered().cloned() else { + #[inline] + pub fn _peek_upper_bound(bound: usize, sequent: &Url) { + emit!(Call( + Exec::call("peek", vec![]) + .with("sequent", sequent.to_string()) + .with("upper-bound", bound.to_string()) + .vec(), + KeymapLayer::Manager + )); + } + + pub fn peek(&mut self, opt: impl Into) -> bool { + let Some(hovered) = self.hovered() else { return self.active_mut().preview.reset(|_| true); }; - let url = &hovered.url; - if hovered.is_dir() { - let position = self.active().history(url).map(|f| (f.offset, f.files.len())); - self.active_mut().preview.folder(url, position, sequent); + let opt = opt.into() as Opt; + if matches!(opt.sequent, Some(ref u) if *u != hovered.url) { return false; } - let Some(mime) = self.mimetype.get(url).cloned() else { + if hovered.is_dir() { + return self.peek_folder(opt, hovered.url.clone()); + } + + let Some(mime) = self.mimetype.get(&hovered.url).cloned() else { return self.active_mut().preview.reset(|_| true); }; - if sequent { - self.active_mut().preview.sequent(url, &mime); - } else { - self.active_mut().preview.go(url, &mime); + let url = hovered.url.clone(); + self.active_mut().preview.arrow(opt.step, &mime); + if let Some(bound) = opt.upper_bound { + self.active_mut().preview.apply_bound(bound); } + + self.active_mut().preview.go(&url, &mime); + false + } + + fn peek_folder(&mut self, opt: Opt, url: Url) -> bool { + let (skip, bound) = self + .active() + .history + .get(&url) + .map(|f| (f.offset, f.files.len().saturating_sub(MANAGER.layout.folder_height()))) + .unwrap_or_default(); + + if opt.sequent.is_some() { + self.active_mut().preview.arrow(opt.step, MIME_DIR); + } else { + self.active_mut().preview.set_skip(skip); + } + + self.active_mut().preview.apply_bound(bound); + self.active_mut().preview.go_folder(url, opt.sequent.is_none()); false } } diff --git a/yazi-core/src/preview/preview.rs b/yazi-core/src/preview/preview.rs index 72f3ba1a..64f01bc0 100644 --- a/yazi-core/src/preview/preview.rs +++ b/yazi-core/src/preview/preview.rs @@ -1,13 +1,13 @@ -use std::time::Duration; +use std::{mem, time::Duration}; use tokio::{pin, task::JoinHandle}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use yazi_adaptor::ADAPTOR; use yazi_config::MANAGER; -use yazi_shared::{MimeKind, PeekError, Url, MIME_DIR}; +use yazi_shared::{MimeKind, PeekError, Url}; use super::Provider; -use crate::{emit, files::{Files, FilesOp}, Highlighter}; +use crate::{emit, files::{Files, FilesOp}, manager::Manager, Highlighter}; #[derive(Default)] pub struct Preview { @@ -19,7 +19,6 @@ pub struct Preview { pub struct PreviewLock { pub url: Url, - pub mime: String, pub skip: usize, pub data: PreviewData, } @@ -33,119 +32,48 @@ pub enum PreviewData { impl Preview { pub fn go(&mut self, url: &Url, mime: &str) { - let kind = MimeKind::new(mime); - if self.same(url, mime) { - return; - } - self.reset(|_| true); - if !self.same_mime(url, mime) { - self.skip = 0; - } + let (url, skip, kind) = (url.clone(), self.skip, MimeKind::new(mime)); - let (url, mime, skip) = (url.clone(), mime.to_owned(), self.skip); self.handle = Some(tokio::spawn(async move { match Provider::auto(kind, &url, skip).await { Ok(data) => { - emit!(Preview(PreviewLock { url, mime, skip, data })); + emit!(Preview(PreviewLock { url, skip, data })); } Err(PeekError::Exceed(max)) => { - emit!(Peek(max, url)); + Manager::_peek_upper_bound(max, &url); } _ => {} } })); } - pub fn folder(&mut self, url: &Url, position: Option<(usize, usize)>, sequent: bool) { - if let Some((_, len)) = position { - self.skip = self.skip.min(len.saturating_sub(MANAGER.layout.preview_height())); - } - - if self.same(url, MIME_DIR) { - return; - } else if !self.same_mime(url, MIME_DIR) { - self.skip = position.map(|(offset, _)| offset).unwrap_or(0); - } - + pub fn go_folder(&mut self, url: Url, in_chunks: bool) { self.reset(|_| true); - emit!(Preview(PreviewLock { - url: url.clone(), - mime: MIME_DIR.to_owned(), - skip: self.skip, - data: PreviewData::Folder, - })); + emit!(Preview(PreviewLock { url: url.clone(), skip: self.skip, data: PreviewData::Folder })); - if sequent { - return; - } - - let url = url.clone(); self.handle = Some(tokio::spawn(async move { let Ok(rx) = Files::from_dir(&url).await else { - emit!(Files(FilesOp::IOErr(url))); + emit!(Files(FilesOp::IOErr(url.clone()))); return; }; - if position.is_some() { - emit!(Files(FilesOp::Full(url, UnboundedReceiverStream::new(rx).collect().await))); + if !in_chunks { + emit!(Files(FilesOp::Full(url.clone(), UnboundedReceiverStream::new(rx).collect().await))); return; } - let rx = UnboundedReceiverStream::new(rx).chunks_timeout(10000, Duration::from_millis(500)); - pin!(rx); + let stream = + UnboundedReceiverStream::new(rx).chunks_timeout(10000, Duration::from_millis(500)); + pin!(stream); let ticket = FilesOp::prepare(&url); - while let Some(chunk) = rx.next().await { + while let Some(chunk) = stream.next().await { emit!(Files(FilesOp::Part(url.clone(), ticket, chunk))); } })); } - pub fn sequent(&mut self, url: &Url, mime: &str) { - let kind = MimeKind::new(mime); - if self.same(url, mime) { - return; - } - - self.handle.take().map(|h| h.abort()); - Highlighter::abort(); - - let (url, mime, skip) = (url.clone(), mime.to_owned(), self.skip); - self.handle = Some(tokio::spawn(async move { - match Provider::auto(kind, &url, skip).await { - Ok(data) => { - emit!(Preview(PreviewLock { url, mime, skip, data })); - } - Err(PeekError::Exceed(max)) => { - emit!(Peek(max, url)); - } - _ => {} - } - })); - } - - pub fn arrow(&mut self, step: isize) -> bool { - let Some(kind) = self.lock.as_ref().map(|l| MimeKind::new(&l.mime)) else { - return false; - }; - - let old = self.skip; - let size = Provider::step_size(kind, step.unsigned_abs()); - - self.skip = if step < 0 { old.saturating_sub(size) } else { old + size }; - self.skip != old - } - - pub fn arrow_max(&mut self, max: usize) -> bool { - if self.skip > max { - self.skip = max; - return true; - } - - false - } - pub fn reset bool>(&mut self, f: F) -> bool { self.handle.take().map(|h| h.abort()); Highlighter::abort(); @@ -166,28 +94,25 @@ impl Preview { } impl Preview { + // --- skip #[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; - } - false + pub fn arrow(&mut self, step: isize, mime: &str) -> bool { + let size = Provider::step_size(MimeKind::new(mime), step.unsigned_abs()); + let skip = if step < 0 { self.skip.saturating_sub(size) } else { self.skip + size }; + mem::replace(&mut self.skip, skip) != skip } #[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; - } - false - } + pub fn set_skip(&mut self, skip: usize) -> bool { mem::replace(&mut self.skip, skip) != skip } #[inline] - pub fn same_path(&self, url: &Url) -> bool { - if let Some(ref lock) = self.lock { - return &lock.url == url; + pub fn apply_bound(&mut self, max: usize) -> bool { + if self.skip <= max { + return false; } - false + + self.skip = max; + true } } diff --git a/yazi-core/src/tab/commands/hidden.rs b/yazi-core/src/tab/commands/hidden.rs index 2d192b59..f66b3cba 100644 --- a/yazi-core/src/tab/commands/hidden.rs +++ b/yazi-core/src/tab/commands/hidden.rs @@ -1,6 +1,6 @@ use yazi_config::keymap::Exec; -use crate::{emit, tab::Tab}; +use crate::{manager::Manager, tab::Tab}; impl Tab { pub fn hidden(&mut self, e: &Exec) -> bool { @@ -10,7 +10,7 @@ impl Tab { _ => !self.conf.show_hidden, }; if self.apply_files_attrs(false) { - emit!(Peek); + Manager::_hover(None); return true; } false diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index ea3fc9ba..2c38a6c0 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -47,18 +47,6 @@ impl From<&Url> for Tab { } impl Tab { - pub fn update_peek(&mut self, max: usize, url: Url) -> bool { - let Some(hovered) = self.current.hovered() else { - return false; - }; - - if url != hovered.url { - return false; - } - - self.preview.arrow_max(max) - } - pub fn update_preview(&mut self, lock: PreviewLock) -> bool { let Some(hovered) = self.current.hovered().map(|h| &h.url) else { return self.preview.reset(|_| true); diff --git a/yazi-core/src/tasks/commands/toggle.rs b/yazi-core/src/tasks/commands/toggle.rs index 1e335701..730c1c75 100644 --- a/yazi-core/src/tasks/commands/toggle.rs +++ b/yazi-core/src/tasks/commands/toggle.rs @@ -1,6 +1,6 @@ use yazi_config::keymap::Exec; -use crate::{emit, tasks::Tasks}; +use crate::tasks::Tasks; pub struct Opt; @@ -14,7 +14,8 @@ impl From<()> for Opt { impl Tasks { pub fn toggle(&mut self, _: impl Into) -> bool { self.visible = !self.visible; - emit!(Peek); // Show/hide preview for images + // TODO: Peek + // emit!(Peek); // Show/hide preview for images true } } diff --git a/yazi-core/src/which/which.rs b/yazi-core/src/which/which.rs index cca92830..a34def36 100644 --- a/yazi-core/src/which/which.rs +++ b/yazi-core/src/which/which.rs @@ -51,6 +51,7 @@ impl Which { #[inline] fn switch(&mut self, state: bool) { self.visible = state; - emit!(Peek); // Show/hide preview for images + // TODO: Peek + // emit!(Peek); // Show/hide preview for images } } diff --git a/yazi-fm/src/app.rs b/yazi-fm/src/app.rs index 5c66d036..c4f5d1ee 100644 --- a/yazi-fm/src/app.rs +++ b/yazi-fm/src/app.rs @@ -115,7 +115,8 @@ impl App { self.cx.manager.current_mut().set_page(true); self.cx.manager.active_mut().preview.reset(|_| true); - self.cx.manager.peek(true); + // TODO: Peek-trigger + // self.cx.manager.peek(true); emit!(Render); } @@ -166,15 +167,7 @@ impl App { Event::Mimetype(mimes) => { if manager.update_mimetype(mimes, tasks) { emit!(Render); - emit!(Peek); - } - } - Event::Peek(sequent) => { - if let Some((max, url)) = sequent { - manager.active_mut().update_peek(max, url); - self.cx.manager.peek(true); - } else { - self.cx.manager.peek(false); + manager.peek(0); } } Event::Preview(lock) => { diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 7b463c09..d73d21b5 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -88,6 +88,7 @@ impl<'a> Executor<'a> { }; } + on!(MANAGER, peek); on!(MANAGER, hover); on!(MANAGER, refresh); on!(MANAGER, quit, &self.cx.tasks); @@ -139,11 +140,6 @@ impl<'a> Executor<'a> { on!(TABS, swap); match exec.cmd.as_bytes() { - b"peek" => { - let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); - self.cx.manager.active_mut().preview.arrow(step); - self.cx.manager.peek(true) - } // Tasks b"tasks_show" => self.cx.tasks.toggle(()), // Help diff --git a/yazi-plugin/src/components/preview.rs b/yazi-plugin/src/components/preview.rs index 546f911b..440e97f0 100644 --- a/yazi-plugin/src/components/preview.rs +++ b/yazi-plugin/src/components/preview.rs @@ -14,17 +14,11 @@ impl<'a> Preview<'a> { impl<'a> Widget for Preview<'a> { fn render(self, area: Rect, buf: &mut Buffer) { - let manager = &self.cx.manager; - let Some(hovered) = manager.hovered().map(|h| &h.url) else { + let Some(ref lock) = self.cx.manager.active().preview.lock else { return; }; - let preview = &manager.active().preview; - if !preview.same_path(hovered) { - return; - } - - match &preview.lock.as_ref().unwrap().data { + match &lock.data { PreviewData::Folder => { Folder::preview(self.cx).render(area, buf); }