Skip to content

Commit

Permalink
feat: allow preloaders to return an optional Error to describe the …
Browse files Browse the repository at this point in the history
…failure (#2253)
  • Loading branch information
sxyazi committed Jan 27, 2025
1 parent da36cd6 commit c061397
Show file tree
Hide file tree
Showing 42 changed files with 297 additions and 230 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ clap = { version = "4.5.27", features = [ "derive" ] }
core-foundation-sys = "0.8.7"
crossterm = { version = "0.28.1", features = [ "event-stream" ] }
dirs = "6.0.0"
foldhash = "0.1.4"
futures = "0.3.31"
globset = "0.4.15"
indexmap = { version = "2.7.1", features = [ "serde" ] }
libc = "0.2.169"
lru = "0.12.5"
md-5 = "0.10.6"
mlua = { version = "0.10.2", features = [ "anyhow", "async", "error-send", "lua54", "macros", "serialize" ] }
objc = "0.2.7"
Expand Down
2 changes: 1 addition & 1 deletion yazi-config/preset/yazi-default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ suppress_preload = false

fetchers = [
# Mimetype
{ id = "mime", name = "*", run = "mime", if = "!mime", prio = "high" },
{ id = "mime", name = "*", run = "mime", prio = "high" },
]
spotters = [
{ name = "*/", run = "folder" },
Expand Down
11 changes: 4 additions & 7 deletions yazi-config/src/plugin/fetcher.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::Path;

use serde::Deserialize;
use yazi_shared::{Condition, MIME_DIR, event::Cmd};
use yazi_shared::{MIME_DIR, event::Cmd};

use crate::{Pattern, Priority};

Expand All @@ -11,8 +11,6 @@ pub struct Fetcher {
pub idx: u8,

pub id: String,
#[serde(rename = "if")]
pub if_: Option<Condition>,
pub name: Option<Pattern>,
pub mime: Option<Pattern>,
pub run: Cmd,
Expand All @@ -22,9 +20,8 @@ pub struct Fetcher {

impl Fetcher {
#[inline]
pub fn matches(&self, path: &Path, mime: &str, f: impl Fn(&str) -> bool + Copy) -> bool {
self.if_.as_ref().and_then(|c| c.eval(f)) != Some(false)
&& (self.mime.as_ref().is_some_and(|p| p.match_mime(mime))
|| self.name.as_ref().is_some_and(|p| p.match_path(path, mime == MIME_DIR)))
pub fn matches(&self, path: &Path, mime: &str) -> bool {
self.mime.as_ref().is_some_and(|p| p.match_mime(mime))
|| self.name.as_ref().is_some_and(|p| p.match_path(path, mime == MIME_DIR))
}
}
15 changes: 2 additions & 13 deletions yazi-config/src/plugin/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ impl Plugin {
&'b self,
path: &'a Path,
mime: &'a str,
factor: impl Fn(&str) -> bool + Copy + 'a,
) -> impl Iterator<Item = &'b Fetcher> + 'a {
let mut seen = HashSet::new();
self.fetchers.iter().filter(move |&f| {
if seen.contains(&f.id) || !f.matches(path, mime, factor) {
if seen.contains(&f.id) || !f.matches(path, mime) {
return false;
}
seen.insert(&f.id);
Expand All @@ -35,12 +34,7 @@ impl Plugin {
pub fn mime_fetchers(&self, files: Vec<File>) -> impl Iterator<Item = (&Fetcher, Vec<File>)> {
let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default();
for f in files {
let factors = |s: &str| match s {
"dummy" => f.cha.is_dummy(),
_ => false,
};

let found = self.fetchers.iter().find(|&g| g.id == "mime" && g.matches(&f.url, "", factors));
let found = self.fetchers.iter().find(|&g| g.id == "mime" && g.matches(&f.url, ""));
if let Some(g) = found {
tasks[g.idx as usize].push(f);
} else {
Expand All @@ -53,11 +47,6 @@ impl Plugin {
})
}

#[inline]
pub fn fetchers_mask(&self) -> u32 {
self.fetchers.iter().fold(0, |n, f| if f.mime.is_some() { n } else { n | 1 << f.idx as u32 })
}

pub fn spotter(&self, path: &Path, mime: &str) -> Option<&Spotter> {
self.spotters.iter().find(|&p| p.matches(path, mime))
}
Expand Down
4 changes: 3 additions & 1 deletion yazi-core/src/manager/commands/update_mimes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ impl Manager {
if repeek {
self.peek(false);
}
tasks.prework_affected(&affected, &self.mimetype);
tasks.fetch_paged(&affected, &self.mimetype);
tasks.preload_paged(&affected, &self.mimetype);

render!();
}
}
13 changes: 1 addition & 12 deletions yazi-core/src/manager/watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ use parking_lot::RwLock;
use tokio::{fs, pin, sync::{mpsc::{self, UnboundedReceiver}, watch}};
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
use tracing::error;
use yazi_config::PLUGIN;
use yazi_dds::Pubsub;
use yazi_fs::{Cha, File, Files, FilesOp, mounts::PARTITIONS, realname_unchecked};
use yazi_plugin::isolate;
use yazi_proxy::WATCHER;
use yazi_shared::{RoCell, event::CmdCow, url::Url};
use yazi_shared::{RoCell, url::Url};

use super::Linked;
use crate::tab::Folder;
Expand Down Expand Up @@ -129,7 +127,6 @@ impl Watcher {

let _permit = WATCHER.acquire().await.unwrap();
let mut ops = Vec::with_capacity(urls.len());
let mut reload = Vec::with_capacity(urls.len());

for u in urls {
let Some((parent, urn)) = u.pair() else { continue };
Expand All @@ -147,18 +144,10 @@ impl Watcher {
continue;
}

if !file.is_dir() {
reload.push(file.clone());
}
ops.push(FilesOp::Upserting(parent, HashMap::from_iter([(urn, file)])));
}

FilesOp::mutate(ops);
for (fetcher, files) in PLUGIN.mime_fetchers(reload) {
if let Err(e) = isolate::fetch(CmdCow::from(&fetcher.run), files).await {
error!("Fetch mime failed in watcher: {e}");
}
}
}
}

Expand Down
35 changes: 8 additions & 27 deletions yazi-core/src/tasks/preload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,12 @@ impl Tasks {
let mut loaded = self.scheduler.prework.loaded.lock();
let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default();
for f in paged {
let mime = mimetype.by_file(f).unwrap_or_default();
let factors = |s: &str| match s {
"mime" => !mime.is_empty(),
"dummy" => f.cha.is_dummy(),
_ => false,
};

for g in PLUGIN.fetchers(&f.url, mime, factors) {
match loaded.get_mut(&f.url) {
let hash = f.hash();
for g in PLUGIN.fetchers(&f.url, mimetype.by_file(f).unwrap_or_default()) {
match loaded.get_mut(&hash) {
Some(n) if *n & (1 << g.idx) != 0 => continue,
Some(n) => *n |= 1 << g.idx,
None => _ = loaded.insert(f.url_owned(), 1 << g.idx),
None => _ = loaded.put(hash, 1 << g.idx),
}
tasks[g.idx as usize].push(f.clone());
}
Expand All @@ -37,31 +31,18 @@ impl Tasks {
pub fn preload_paged(&self, paged: &[File], mimetype: &Mimetype) {
let mut loaded = self.scheduler.prework.loaded.lock();
for f in paged {
let mime = mimetype.by_file(f).unwrap_or_default();
for p in PLUGIN.preloaders(&f.url, mime) {
match loaded.get_mut(&f.url) {
let hash = f.hash();
for p in PLUGIN.preloaders(&f.url, mimetype.by_file(f).unwrap_or_default()) {
match loaded.get_mut(&hash) {
Some(n) if *n & (1 << p.idx) != 0 => continue,
Some(n) => *n |= 1 << p.idx,
None => _ = loaded.insert(f.url_owned(), 1 << p.idx),
None => _ = loaded.put(hash, 1 << p.idx),
}
self.scheduler.preload_paged(p, f);
}
}
}

pub fn prework_affected(&self, affected: &[File], mimetype: &Mimetype) {
let mask = PLUGIN.fetchers_mask();
{
let mut loaded = self.scheduler.prework.loaded.lock();
for f in affected {
loaded.get_mut(&f.url).map(|n| *n &= mask);
}
}

self.fetch_paged(affected, mimetype);
self.preload_paged(affected, mimetype);
}

pub fn prework_sorted(&self, targets: &Files) {
if targets.sorter().by != SortBy::Size {
return;
Expand Down
4 changes: 2 additions & 2 deletions yazi-fm/src/lives/folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::ops::{Deref, Range};

use mlua::{AnyUserData, Lua, UserData, UserDataFields};
use yazi_config::LAYOUT;
use yazi_plugin::{bindings::Cast, url::Url};
use yazi_plugin::url::Url;

use super::{File, Files, Lives};

Expand Down Expand Up @@ -50,7 +50,7 @@ impl Folder {

impl UserData for Folder {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("cwd", |lua, me| Url::cast(lua, me.url.to_owned()));
fields.add_field_method_get("cwd", |_, me| Ok(Url(me.url.to_owned())));
fields.add_field_method_get("files", |_, me| Files::make(0..me.files.len(), me, me.tab()));
fields.add_field_method_get("stage", |lua, me| lua.create_any_userdata(me.stage));
fields.add_field_method_get("window", |_, me| Files::make(me.window.clone(), me, me.tab()));
Expand Down
4 changes: 2 additions & 2 deletions yazi-fm/src/lives/selected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::ops::Deref;

use indexmap::{IndexMap, map::Keys};
use mlua::{AnyUserData, IntoLuaMulti, MetaMethod, UserData, UserDataMethods, UserDataRefMut};
use yazi_plugin::{bindings::Cast, url::Url};
use yazi_plugin::url::Url;

use super::{Iter, Lives};

Expand Down Expand Up @@ -35,7 +35,7 @@ impl UserData for Selected {
let iter = lua.create_function(
|lua, mut iter: UserDataRefMut<Iter<Keys<yazi_shared::url::Url, u64>, _>>| {
if let Some(next) = iter.next() {
(next.0, Url::cast(lua, next.1.clone())?).into_lua_multi(lua)
(next.0, Url(next.1.clone())).into_lua_multi(lua)
} else {
().into_lua_multi(lua)
}
Expand Down
4 changes: 2 additions & 2 deletions yazi-fm/src/lives/yanked.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{collections::hash_set, ops::Deref};

use mlua::{AnyUserData, IntoLuaMulti, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRefMut};
use yazi_plugin::{bindings::Cast, url::Url};
use yazi_plugin::url::Url;

use super::{Iter, Lives};

Expand Down Expand Up @@ -37,7 +37,7 @@ impl UserData for Yanked {
let iter = lua.create_function(
|lua, mut iter: UserDataRefMut<Iter<hash_set::Iter<yazi_shared::url::Url>, _>>| {
if let Some(next) = iter.next() {
(next.0, Url::cast(lua, next.1.clone())?).into_lua_multi(lua)
(next.0, Url(next.1.clone())).into_lua_multi(lua)
} else {
().into_lua_multi(lua)
}
Expand Down
1 change: 1 addition & 0 deletions yazi-fs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ anyhow = { workspace = true }
arc-swap = "1.7.1"
bitflags = { workspace = true }
dirs = { workspace = true }
foldhash = { workspace = true }
futures = { workspace = true }
parking_lot = { workspace = true }
regex = { workspace = true }
Expand Down
15 changes: 14 additions & 1 deletion yazi-fs/src/file.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{ffi::OsStr, fs::{FileType, Metadata}, ops::Deref};
use std::{ffi::OsStr, fs::{FileType, Metadata}, hash::{BuildHasher, Hash, Hasher}, ops::Deref};

use anyhow::Result;
use tokio::fs;
Expand Down Expand Up @@ -48,6 +48,19 @@ impl File {
}
}

#[inline]
pub fn hash(&self) -> u64 {
let mut h = foldhash::fast::FixedState::default().build_hasher();
self.url.hash(&mut h);
h.write_u8(0);
self.cha.len.hash(&mut h);
h.write_u8(0);
self.cha.mtime.hash(&mut h);
h.write_u8(0);
self.cha.btime.hash(&mut h);
h.finish()
}

#[inline]
pub fn rebase(&self, parent: &Url) -> Self {
Self {
Expand Down
14 changes: 9 additions & 5 deletions yazi-plugin/preset/plugins/font.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ local M = {}

function M:peek(job)
local start, cache = os.clock(), ya.file_cache(job)
if not cache or self:preload(job) ~= 1 then
if not cache then
return
end

local ok, err = self:preload(job)
if not ok or err then
return
end

Expand All @@ -18,7 +23,7 @@ function M:seek() end
function M:preload(job)
local cache = ya.file_cache(job)
if not cache or fs.cha(cache) then
return 1
return true
end

local status, err = Command("magick"):args({
Expand All @@ -40,10 +45,9 @@ function M:preload(job)
}):status()

if status then
return status.success and 1 or 2
return status.success
else
ya.err("Failed to start `magick`, error: " .. err)
return 0
return true, Err("Failed to start `magick`, error: %s", err)
end
end

Expand Down
4 changes: 2 additions & 2 deletions yazi-plugin/preset/plugins/image.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ function M:seek() end
function M:preload(job)
local cache = ya.file_cache(job)
if not cache or fs.cha(cache) then
return 1
return true
end

return ya.image_precache(job.file.url, cache) and 1 or 2
return ya.image_precache(job.file.url, cache)
end

function M:spot(job)
Expand Down
14 changes: 9 additions & 5 deletions yazi-plugin/preset/plugins/magick.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ local M = {}

function M:peek(job)
local start, cache = os.clock(), ya.file_cache(job)
if not cache or self:preload(job) ~= 1 then
if not cache then
return
end

local ok, err = self:preload(job)
if not ok or err then
return
end

Expand All @@ -16,7 +21,7 @@ function M:seek() end
function M:preload(job)
local cache = ya.file_cache(job)
if not cache or fs.cha(cache) then
return 1
return true
end

local status, err = Command("magick")
Expand All @@ -36,10 +41,9 @@ function M:preload(job)
:status()

if status then
return status.success and 1 or 2
return status.success
else
ya.err("Failed to start `magick`, error: " .. err)
return 0
return true, Err("Failed to start `magick`, error: %s", err)
end
end

Expand Down
Loading

0 comments on commit c061397

Please sign in to comment.