mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-24 00:01:03 +00:00
fix: one file's mime-type changed multiple times without triggering a preview again (#1682)
This commit is contained in:
parent
631afd09ee
commit
5b66192332
10 changed files with 66 additions and 58 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
|
@ -1774,9 +1774,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.30"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
|
|
@ -2265,9 +2265,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "simdutf8"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
|
|
@ -2400,18 +2400,18 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.63"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static SHOWN: RoCell<arc_swap::ArcSwapOption<ratatui::layout::Rect>> = RoCell::n
|
|||
|
||||
pub fn init() {
|
||||
// Tmux support
|
||||
TMUX.init(env_exists("TMUX") && env_exists("TMUX_PANE"));
|
||||
TMUX.init(env_exists("TMUX_PANE") && env_exists("TMUX"));
|
||||
ESCAPE.init(if *TMUX { "\x1b\x1b" } else { "\x1b" });
|
||||
START.init(if *TMUX { "\x1bPtmux;\x1b\x1b" } else { "\x1b" });
|
||||
CLOSE.init(if *TMUX { "\x1b\\" } else { "" });
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@ tokio = { workspace = true }
|
|||
toml_edit = "0.22.21"
|
||||
|
||||
[build-dependencies]
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.3.3" }
|
||||
|
||||
# External build dependencies
|
||||
anyhow = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -27,13 +27,17 @@ impl From<bool> for Opt {
|
|||
impl Manager {
|
||||
pub fn peek(&mut self, opt: impl Into<Opt>) {
|
||||
let Some(hovered) = self.hovered().cloned() else {
|
||||
return render!(self.active_mut().preview.reset());
|
||||
return self.active_mut().preview.reset();
|
||||
};
|
||||
|
||||
let mime = self.mimetype.get_owned(&hovered.url).unwrap_or_default();
|
||||
let folder = self.active().hovered_folder().map(|f| (f.offset, f.cha));
|
||||
|
||||
if !self.active().preview.same_url(&hovered.url) {
|
||||
self.active_mut().preview.skip = folder.map(|f| f.0).unwrap_or_default();
|
||||
render!(self.active_mut().preview.reset());
|
||||
}
|
||||
if !self.active().preview.same_file(&hovered, &mime) {
|
||||
self.active_mut().preview.reset();
|
||||
}
|
||||
|
||||
let opt = opt.into() as Opt;
|
||||
|
|
@ -52,13 +56,8 @@ impl Manager {
|
|||
|
||||
if hovered.is_dir() {
|
||||
self.active_mut().preview.go_folder(hovered, folder.map(|f| f.1), opt.force);
|
||||
return;
|
||||
}
|
||||
|
||||
let mime = self.mimetype.get_owned(&hovered.url).unwrap_or_default();
|
||||
if !mime.is_empty() {
|
||||
// Wait till mimetype is resolved to avoid flickering
|
||||
self.active_mut().preview.go(hovered, &mime, opt.force);
|
||||
} else {
|
||||
self.active_mut().preview.go(hovered, mime.into(), opt.force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ impl From<Cmd> for Opt {
|
|||
impl Manager {
|
||||
pub fn seek(&mut self, opt: impl Into<Opt>) {
|
||||
let Some(hovered) = self.hovered() else {
|
||||
return render!(self.active_mut().preview.reset());
|
||||
return self.active_mut().preview.reset();
|
||||
};
|
||||
|
||||
let mime = if hovered.is_dir() {
|
||||
|
|
@ -24,11 +24,11 @@ impl Manager {
|
|||
} else if let Some(s) = self.mimetype.get(&hovered.url) {
|
||||
s
|
||||
} else {
|
||||
return render!(self.active_mut().preview.reset());
|
||||
return self.active_mut().preview.reset();
|
||||
};
|
||||
|
||||
let Some(previewer) = PLUGIN.previewer(&hovered.url, mime) else {
|
||||
return render!(self.active_mut().preview.reset());
|
||||
return self.active_mut().preview.reset();
|
||||
};
|
||||
|
||||
let opt = opt.into() as Opt;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ impl TryFrom<Cmd> for Opt {
|
|||
impl Tab {
|
||||
pub fn preview(&mut self, opt: impl TryInto<Opt>) {
|
||||
let Some(hovered) = self.current.hovered().map(|h| &h.url) else {
|
||||
return render!(self.preview.reset());
|
||||
return self.preview.reset();
|
||||
};
|
||||
|
||||
let Ok(opt) = opt.try_into() else {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::time::Duration;
|
||||
use std::{borrow::Cow, ops::Not, time::Duration};
|
||||
|
||||
use tokio::{pin, task::JoinHandle};
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
|
|
@ -7,7 +7,7 @@ use yazi_adapter::ADAPTOR;
|
|||
use yazi_config::PLUGIN;
|
||||
use yazi_fs::Files;
|
||||
use yazi_plugin::{external::Highlighter, isolate, utils::PreviewLock};
|
||||
use yazi_shared::{MIME_DIR, fs::{Cha, File, FilesOp, Url}};
|
||||
use yazi_shared::{MIME_DIR, fs::{Cha, File, FilesOp, Url}, render};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Preview {
|
||||
|
|
@ -19,32 +19,30 @@ pub struct Preview {
|
|||
}
|
||||
|
||||
impl Preview {
|
||||
pub fn go(&mut self, file: File, mime: &str, force: bool) {
|
||||
if !force && self.content_unchanged(&file.url, file.cha) {
|
||||
pub fn go(&mut self, file: File, mime: Cow<'static, str>, force: bool) {
|
||||
if mime.is_empty() {
|
||||
return; // Wait till mimetype is resolved to avoid flickering
|
||||
} else if !force && self.same_lock(&file, &mime) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(previewer) = PLUGIN.previewer(&file.url, mime) else {
|
||||
self.reset();
|
||||
return;
|
||||
let Some(previewer) = PLUGIN.previewer(&file.url, &mime) else {
|
||||
return self.reset();
|
||||
};
|
||||
|
||||
self.abort();
|
||||
if previewer.sync {
|
||||
isolate::peek_sync(&previewer.run, file, self.skip);
|
||||
isolate::peek_sync(&previewer.run, file, mime, self.skip);
|
||||
} else {
|
||||
self.previewer_ct = Some(isolate::peek(&previewer.run, file, self.skip));
|
||||
self.previewer_ct = Some(isolate::peek(&previewer.run, file, mime, self.skip));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn go_folder(&mut self, file: File, dir: Option<Cha>, force: bool) {
|
||||
let (cha, cwd) = (file.cha, file.url_owned());
|
||||
self.go(file, MIME_DIR, force);
|
||||
|
||||
if self.content_unchanged(&cwd, cha) {
|
||||
return;
|
||||
}
|
||||
let cwd = self.same_file(&file, MIME_DIR).not().then(|| file.url_owned());
|
||||
self.go(file, Cow::Borrowed(MIME_DIR), force);
|
||||
|
||||
let Some(cwd) = cwd else { return };
|
||||
self.folder_loader.take().map(|h| h.abort());
|
||||
self.folder_loader = Some(tokio::spawn(async move {
|
||||
let Some(new) = Files::assert_stale(&cwd, dir.unwrap_or(Cha::dummy())).await else {
|
||||
|
|
@ -71,10 +69,10 @@ impl Preview {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reset(&mut self) -> bool {
|
||||
pub fn reset(&mut self) {
|
||||
self.abort();
|
||||
ADAPTOR.image_hide().ok();
|
||||
self.lock.take().is_some()
|
||||
render!(self.lock.take().is_some())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -84,15 +82,16 @@ impl Preview {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn same_url(&self, url: &Url) -> bool {
|
||||
matches!(self.lock, Some(ref lock) if lock.url == *url)
|
||||
pub fn same_url(&self, url: &Url) -> bool { self.lock.as_ref().is_some_and(|l| *url == l.url) }
|
||||
|
||||
#[inline]
|
||||
pub fn same_file(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_url(&file.url)
|
||||
&& self.lock.as_ref().is_some_and(|l| file.cha.hits(l.cha) && mime == l.mime)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn content_unchanged(&self, url: &Url, cha: Cha) -> bool {
|
||||
match &self.lock {
|
||||
Some(l) => *url == l.url && self.skip == l.skip && cha.hits(l.cha),
|
||||
None => false,
|
||||
}
|
||||
pub fn same_lock(&self, file: &File, mime: &str) -> bool {
|
||||
self.same_file(file, mime) && self.lock.as_ref().is_some_and(|l| self.skip == l.skip)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ use crossterm::{execute, queue, terminal::{BeginSynchronizedUpdate, EndSynchroni
|
|||
use ratatui::{CompletedFrame, backend::{Backend, CrosstermBackend}, buffer::Buffer};
|
||||
use scopeguard::defer;
|
||||
use yazi_plugin::elements::COLLISION;
|
||||
use yazi_shared::event::NEED_RENDER;
|
||||
|
||||
use crate::{app::App, lives::Lives, root::Root};
|
||||
|
||||
impl App {
|
||||
pub(crate) fn render(&mut self) {
|
||||
let Some(term) = &mut self.term else {
|
||||
return;
|
||||
};
|
||||
NEED_RENDER.store(false, Ordering::Relaxed);
|
||||
let Some(term) = &mut self.term else { return };
|
||||
|
||||
queue!(stderr(), BeginSynchronizedUpdate).ok();
|
||||
defer! { execute!(stderr(), EndSynchronizedUpdate).ok(); }
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use mlua::{ExternalError, ExternalResult, HookTriggers, Table, TableExt};
|
||||
use tokio::{runtime::Handle, select};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
|
@ -8,7 +10,12 @@ use yazi_shared::{Layer, emit, event::Cmd};
|
|||
use super::slim_lua;
|
||||
use crate::{LUA, Opt, OptCallback, bindings::{Cast, Window}, elements::Rect, file::File, loader::LOADER};
|
||||
|
||||
pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> CancellationToken {
|
||||
pub fn peek(
|
||||
cmd: &Cmd,
|
||||
file: yazi_shared::fs::File,
|
||||
mime: Cow<'static, str>,
|
||||
skip: usize,
|
||||
) -> CancellationToken {
|
||||
let ct = CancellationToken::new();
|
||||
|
||||
let name = cmd.name.to_owned();
|
||||
|
|
@ -31,6 +38,7 @@ pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> Cancellation
|
|||
return Err("unloaded plugin".into_lua_err());
|
||||
};
|
||||
plugin.raw_set("file", File::cast(&lua, file)?)?;
|
||||
plugin.raw_set("_mime", mime)?;
|
||||
plugin.raw_set("skip", skip)?;
|
||||
plugin.raw_set("area", Rect::cast(&lua, LAYOUT.load().preview)?)?;
|
||||
plugin.raw_set("window", Window::default())?;
|
||||
|
|
@ -55,9 +63,10 @@ pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> Cancellation
|
|||
ct
|
||||
}
|
||||
|
||||
pub fn peek_sync(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) {
|
||||
pub fn peek_sync(cmd: &Cmd, file: yazi_shared::fs::File, mime: Cow<'static, str>, skip: usize) {
|
||||
let cb: OptCallback = Box::new(move |_, plugin| {
|
||||
plugin.raw_set("file", File::cast(&LUA, file)?)?;
|
||||
plugin.raw_set("_mime", mime)?;
|
||||
plugin.raw_set("skip", skip)?;
|
||||
plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?;
|
||||
plugin.raw_set("window", Window::default())?;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ use super::Utils;
|
|||
use crate::{bindings::Window, cast_to_renderable, elements::{Paragraph, RectRef, Renderable, WRAP, WRAP_NO}, external::Highlighter, file::FileRef};
|
||||
|
||||
pub struct PreviewLock {
|
||||
pub url: yazi_shared::fs::Url,
|
||||
pub cha: yazi_shared::fs::Cha,
|
||||
pub url: yazi_shared::fs::Url,
|
||||
pub cha: yazi_shared::fs::Cha,
|
||||
pub mime: String,
|
||||
|
||||
pub skip: usize,
|
||||
pub window: Window,
|
||||
|
|
@ -18,10 +19,12 @@ impl<'a> TryFrom<Table<'a>> for PreviewLock {
|
|||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(t: Table) -> Result<Self, Self::Error> {
|
||||
let file: FileRef = t.raw_get("file")?;
|
||||
let file: FileRef = t.raw_get("file")?; // TODO: use `_file` instead of `file`
|
||||
Ok(Self {
|
||||
cha: file.cha,
|
||||
url: file.url_owned(),
|
||||
url: file.url_owned(),
|
||||
cha: file.cha,
|
||||
mime: t.raw_get("_mime")?,
|
||||
|
||||
skip: t.raw_get("skip")?,
|
||||
window: t.raw_get("window")?,
|
||||
data: Default::default(),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue