This commit is contained in:
sxyazi 2023-11-23 08:47:01 +08:00
parent ff369f4d15
commit 1270fd15f9
No known key found for this signature in database
9 changed files with 108 additions and 52 deletions

View file

@ -3,32 +3,33 @@ use yazi_shared::{Url, MIME_DIR};
use crate::{emit, manager::Manager};
#[derive(Debug)]
pub struct Opt {
step: isize,
sequent: Option<Url>,
upper_bound: Option<usize>,
only_if: Option<Url>,
upper_bound: bool,
}
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()),
only_if: e.named.get("only-if").map(Url::from),
upper_bound: e.named.contains_key("upper-bound"),
}
}
}
impl From<isize> for Opt {
fn from(step: isize) -> Self { Self { step, sequent: None, upper_bound: None } }
fn from(step: isize) -> Self { Self { step, only_if: None, upper_bound: false } }
}
impl Manager {
#[inline]
pub fn _peek_upper_bound(bound: usize, sequent: &Url) {
pub fn _peek_upper_bound(bound: usize, only_if: &Url) {
emit!(Call(
Exec::call("peek", vec![])
.with("sequent", sequent.to_string())
.with("upper-bound", bound.to_string())
Exec::call("peek", vec![bound.to_string()])
.with("only-if", only_if.to_string())
.with_bool("upper-bound", true)
.vec(),
KeymapLayer::Manager
));
@ -36,11 +37,11 @@ impl Manager {
pub fn peek(&mut self, opt: impl Into<Opt>) -> bool {
let Some(hovered) = self.hovered() else {
return self.active_mut().preview.reset(|_| true);
return self.active_mut().preview.reset();
};
let opt = opt.into() as Opt;
if matches!(opt.sequent, Some(ref u) if *u != hovered.url) {
if matches!(opt.only_if, Some(ref u) if *u != hovered.url) {
return false;
}
@ -49,35 +50,37 @@ impl Manager {
}
let Some(mime) = self.mimetype.get(&hovered.url).cloned() else {
return self.active_mut().preview.reset(|_| true);
return self.active_mut().preview.reset();
};
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);
let (url, cha) = (hovered.url.clone(), hovered.cha);
if self.active().preview.same_url(&url) {
self.active_mut().preview.arrow(opt.step, &mime);
} else if opt.upper_bound {
self.active_mut().preview.apply_bound(opt.step as usize);
} else {
self.active_mut().preview.set_skip(0);
}
self.active_mut().preview.go(&url, &mime);
self.active_mut().preview.go(&url, cha, &mime);
false
}
fn peek_folder(&mut self, opt: Opt, url: Url) -> bool {
let (skip, bound) = self
.active()
.history
.get(&url)
let folder = self.active().history.get(&url);
let (skip, bound) = folder
.map(|f| (f.offset, f.files.len().saturating_sub(MANAGER.layout.folder_height())))
.unwrap_or_default();
if opt.sequent.is_some() {
if self.active().preview.same_url(&url) {
self.active_mut().preview.arrow(opt.step, MIME_DIR);
} else {
self.active_mut().preview.set_skip(skip);
self.active_mut().preview.apply_bound(bound);
return false;
}
self.active_mut().preview.apply_bound(bound);
self.active_mut().preview.go_folder(url, opt.sequent.is_none());
let in_chunks = folder.is_none();
self.active_mut().preview.set_skip(skip);
self.active_mut().preview.go_folder(url, in_chunks);
false
}
}

View file

@ -31,7 +31,7 @@ impl Tabs {
#[inline]
pub(super) fn set_idx(&mut self, idx: usize) {
self.idx = idx;
self.active_mut().preview.reset(|l| l.is_image());
self.active_mut().preview.reset_image();
Manager::_refresh();
}
}

View file

@ -3,3 +3,5 @@ mod provider;
pub use preview::*;
use provider::*;
pub static COLLISION: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);

View file

@ -4,7 +4,7 @@ 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};
use yazi_shared::{Cha, MimeKind, PeekError, Url};
use super::Provider;
use crate::{emit, files::{Files, FilesOp}, manager::Manager, Highlighter};
@ -19,6 +19,7 @@ pub struct Preview {
pub struct PreviewLock {
pub url: Url,
pub cha: Option<Cha>,
pub skip: usize,
pub data: PreviewData,
}
@ -31,14 +32,18 @@ pub enum PreviewData {
}
impl Preview {
pub fn go(&mut self, url: &Url, mime: &str) {
self.reset(|_| true);
let (url, skip, kind) = (url.clone(), self.skip, MimeKind::new(mime));
pub fn go(&mut self, url: &Url, cha: Cha, mime: &str) {
if self.content_unchanged(url, &cha) {
return;
}
self.reset();
let (url, kind, skip) = (url.clone(), MimeKind::new(mime), self.skip);
self.handle = Some(tokio::spawn(async move {
match Provider::auto(kind, &url, skip).await {
Ok(data) => {
emit!(Preview(PreviewLock { url, skip, data }));
emit!(Preview(PreviewLock { url, cha: Some(cha), skip, data }));
}
Err(PeekError::Exceed(max)) => {
Manager::_peek_upper_bound(max, &url);
@ -49,8 +54,13 @@ impl Preview {
}
pub fn go_folder(&mut self, url: Url, in_chunks: bool) {
self.reset(|_| true);
emit!(Preview(PreviewLock { url: url.clone(), skip: self.skip, data: PreviewData::Folder }));
self.reset();
self.lock = Some(PreviewLock {
url: url.clone(),
cha: None,
skip: self.skip,
data: PreviewData::Folder,
});
self.handle = Some(tokio::spawn(async move {
let Ok(rx) = Files::from_dir(&url).await else {
@ -74,7 +84,7 @@ impl Preview {
}));
}
pub fn reset<F: FnOnce(&PreviewLock) -> bool>(&mut self, f: F) -> bool {
pub fn reset(&mut self) -> bool {
self.handle.take().map(|h| h.abort());
Highlighter::abort();
ADAPTOR.image_hide(MANAGER.layout.image_rect()).ok();
@ -83,14 +93,49 @@ impl Preview {
return false;
};
if !f(lock) {
return false;
}
let b = !lock.is_image();
self.lock = None;
b
}
pub fn reset_image(&mut self) -> bool {
if !matches!(self.lock, Some(ref lock) if lock.is_image()) {
return false;
}
self.reset();
true
}
#[inline]
pub fn same_url(&self, url: &Url) -> bool {
matches!(self.lock, Some(ref lock) if lock.url == *url)
}
fn content_unchanged(&self, url: &Url, cha: &Cha) -> bool {
let Some(lock) = &self.lock else {
return false;
};
let Some(cha_) = &lock.cha else {
return false;
};
*url == lock.url
&& self.skip == lock.skip
&& cha.len == cha_.len
&& cha.modified == cha_.modified
&& cha.meta == cha_.meta
&& {
#[cfg(unix)]
{
cha.permissions == cha_.permissions
}
#[cfg(windows)]
{
true
}
}
}
}
impl Preview {
@ -106,12 +151,12 @@ impl Preview {
pub fn set_skip(&mut self, skip: usize) -> bool { mem::replace(&mut self.skip, skip) != skip }
#[inline]
pub fn apply_bound(&mut self, max: usize) -> bool {
if self.skip <= max {
pub fn apply_bound(&mut self, upper: usize) -> bool {
if self.skip <= upper {
return false;
}
self.skip = max;
self.skip = upper;
true
}
}

View file

@ -76,7 +76,7 @@ impl Tab {
handle.abort();
}
if self.current.cwd.is_search() {
self.preview.reset(|l| l.is_image());
self.preview.reset_image();
let rep = self.history_new(&self.current.cwd.to_regular());
drop(mem::replace(&mut self.current, rep));

View file

@ -49,7 +49,7 @@ impl From<&Url> for Tab {
impl Tab {
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);
return self.preview.reset();
};
if lock.url != *hovered {

View file

@ -1,11 +1,11 @@
use std::ffi::OsString;
use std::{ffi::OsString, sync::atomic::Ordering};
use anyhow::{Ok, Result};
use crossterm::event::KeyEvent;
use ratatui::{backend::Backend, prelude::Rect};
use tokio::sync::oneshot;
use yazi_config::{keymap::{Exec, Key, KeymapLayer}, BOOT};
use yazi_core::{emit, files::FilesOp, input::InputMode, manager::Manager, Ctx, Event};
use yazi_core::{emit, files::FilesOp, input::InputMode, manager::Manager, preview::COLLISION, Ctx, Event};
use yazi_shared::Term;
use crate::{Executor, Logs, Panic, Root, Signals};
@ -81,14 +81,17 @@ impl App {
return Ok(());
};
COLLISION.store(false, Ordering::Relaxed);
let frame = term.draw(|f| {
yazi_plugin::scope(&self.cx, |_| {
f.render_widget(Root::new(&self.cx), f.size());
});
})?;
if !COLLISION.load(Ordering::Relaxed) {
return Ok(());
}
let mut patches = Vec::new();
// TODO: find a more efficient way to do this
for x in frame.area.left()..frame.area.right() {
for y in frame.area.top()..frame.area.bottom() {
let cell = frame.buffer.get(x, y);
@ -114,14 +117,13 @@ impl App {
}
self.cx.manager.current_mut().set_page(true);
self.cx.manager.active_mut().preview.reset(|_| true);
// TODO: Peek-trigger
// self.cx.manager.peek(true);
self.cx.manager.active_mut().preview.reset();
self.cx.manager.peek(0);
emit!(Render);
}
fn dispatch_stop(&mut self, state: bool, tx: Option<oneshot::Sender<()>>) {
self.cx.manager.active_mut().preview.reset(|l| l.is_image());
self.cx.manager.active_mut().preview.reset_image();
if state {
self.signals.stop_term(true);
self.term = None;

View file

@ -1,6 +1,9 @@
use std::sync::atomic::Ordering;
use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget};
use yazi_adaptor::ADAPTOR;
use yazi_config::MANAGER;
use yazi_core::preview::COLLISION;
pub(crate) struct Clear;
@ -30,6 +33,7 @@ impl Widget for Clear {
};
ADAPTOR.image_hide(r).ok();
COLLISION.store(true, Ordering::Relaxed);
for x in r.left()..r.right() {
for y in r.top()..r.bottom() {
buf.get_mut(x, y).set_skip(true);

View file

@ -3,7 +3,7 @@ use std::{fs::Metadata, time::SystemTime};
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ChaMeta: u8 {
const DIR = 0b00000001;