From 4d39194cd81d50feacbd62ad06047be0c23dbd59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Wed, 1 Oct 2025 20:03:41 +0800 Subject: [PATCH] feat!: folder mime-type support (#3222) --- README.md | 8 + yazi-actor/src/actor.rs | 2 +- yazi-actor/src/cmp/arrow.rs | 2 +- yazi-actor/src/cmp/close.rs | 2 +- yazi-actor/src/cmp/show.rs | 2 +- yazi-actor/src/cmp/trigger.rs | 2 +- yazi-actor/src/confirm/arrow.rs | 2 +- yazi-actor/src/confirm/close.rs | 2 +- yazi-actor/src/confirm/show.rs | 2 +- yazi-actor/src/context.rs | 4 +- yazi-actor/src/help/arrow.rs | 2 +- yazi-actor/src/help/escape.rs | 2 +- yazi-actor/src/help/filter.rs | 2 +- yazi-actor/src/help/toggle.rs | 2 +- yazi-actor/src/input/close.rs | 2 +- yazi-actor/src/input/escape.rs | 2 +- yazi-actor/src/input/show.rs | 2 +- yazi-actor/src/lives/file.rs | 4 +- yazi-actor/src/mgr/arrow.rs | 2 +- yazi-actor/src/mgr/back.rs | 2 +- yazi-actor/src/mgr/bulk_rename.rs | 10 +- yazi-actor/src/mgr/cd.rs | 2 +- yazi-actor/src/mgr/close.rs | 2 +- yazi-actor/src/mgr/copy.rs | 2 +- yazi-actor/src/mgr/create.rs | 10 +- yazi-actor/src/mgr/download.rs | 58 ++++ yazi-actor/src/mgr/enter.rs | 2 +- yazi-actor/src/mgr/escape.rs | 2 +- yazi-actor/src/mgr/filter.rs | 2 +- yazi-actor/src/mgr/filter_do.rs | 2 +- yazi-actor/src/mgr/find.rs | 2 +- yazi-actor/src/mgr/find_arrow.rs | 2 +- yazi-actor/src/mgr/find_do.rs | 2 +- yazi-actor/src/mgr/follow.rs | 2 +- yazi-actor/src/mgr/forward.rs | 2 +- yazi-actor/src/mgr/hardlink.rs | 2 +- yazi-actor/src/mgr/hidden.rs | 2 +- yazi-actor/src/mgr/hover.rs | 2 +- yazi-actor/src/mgr/leave.rs | 2 +- yazi-actor/src/mgr/linemode.rs | 2 +- yazi-actor/src/mgr/link.rs | 2 +- yazi-actor/src/mgr/mod.rs | 2 + yazi-actor/src/mgr/open.rs | 133 +++------ yazi-actor/src/mgr/open_do.rs | 50 ++++ yazi-actor/src/mgr/paste.rs | 2 +- yazi-actor/src/mgr/peek.rs | 4 +- yazi-actor/src/mgr/quit.rs | 19 +- yazi-actor/src/mgr/refresh.rs | 2 +- yazi-actor/src/mgr/remove.rs | 2 +- yazi-actor/src/mgr/rename.rs | 8 +- yazi-actor/src/mgr/reveal.rs | 2 +- yazi-actor/src/mgr/search.rs | 2 +- yazi-actor/src/mgr/seek.rs | 6 +- yazi-actor/src/mgr/shell.rs | 4 +- yazi-actor/src/mgr/sort.rs | 2 +- yazi-actor/src/mgr/spot.rs | 4 +- yazi-actor/src/mgr/suspend.rs | 2 +- yazi-actor/src/mgr/tab_close.rs | 2 +- yazi-actor/src/mgr/tab_create.rs | 2 +- yazi-actor/src/mgr/tab_swap.rs | 2 +- yazi-actor/src/mgr/tab_switch.rs | 2 +- yazi-actor/src/mgr/toggle.rs | 2 +- yazi-actor/src/mgr/toggle_all.rs | 2 +- yazi-actor/src/mgr/unyank.rs | 2 +- yazi-actor/src/mgr/update_files.rs | 2 +- yazi-actor/src/mgr/update_mimes.rs | 4 +- yazi-actor/src/mgr/update_paged.rs | 2 +- yazi-actor/src/mgr/update_peeked.rs | 2 +- yazi-actor/src/mgr/update_spotted.rs | 2 +- yazi-actor/src/mgr/update_yanked.rs | 2 +- yazi-actor/src/mgr/visual_mode.rs | 2 +- yazi-actor/src/mgr/watch.rs | 2 +- yazi-actor/src/mgr/yank.rs | 2 +- yazi-actor/src/pick/arrow.rs | 2 +- yazi-actor/src/pick/close.rs | 2 +- yazi-actor/src/pick/show.rs | 2 +- yazi-actor/src/spot/arrow.rs | 2 +- yazi-actor/src/spot/close.rs | 2 +- yazi-actor/src/spot/copy.rs | 2 +- yazi-actor/src/spot/swipe.rs | 2 +- yazi-actor/src/tasks/arrow.rs | 2 +- yazi-actor/src/tasks/cancel.rs | 2 +- yazi-actor/src/tasks/close.rs | 2 +- yazi-actor/src/tasks/inspect.rs | 2 +- yazi-actor/src/tasks/open_with.rs | 4 +- yazi-actor/src/tasks/process_exec.rs | 2 +- yazi-actor/src/tasks/show.rs | 2 +- yazi-actor/src/tasks/update_succeed.rs | 2 +- yazi-actor/src/which/callback.rs | 2 +- yazi-actor/src/which/show.rs | 2 +- yazi-boot/src/actions/debug.rs | 10 +- yazi-cli/src/package/hash.rs | 5 +- yazi-cli/src/package/package.rs | 9 +- yazi-cli/src/shared/shared.rs | 5 +- yazi-config/preset/yazi-default.toml | 25 +- yazi-config/src/open/open.rs | 21 +- yazi-config/src/pattern.rs | 12 +- yazi-config/src/plugin/fetcher.rs | 7 +- yazi-config/src/plugin/plugin.rs | 19 +- yazi-config/src/plugin/preloader.rs | 7 +- yazi-config/src/plugin/previewer.rs | 7 +- yazi-config/src/plugin/spotter.rs | 7 +- yazi-config/src/vfs/provider.rs | 36 ++- yazi-config/src/vfs/vfs.rs | 6 +- yazi-core/src/mgr/mimetype.rs | 15 +- yazi-core/src/spot/spot.rs | 2 +- yazi-core/src/tab/preview.rs | 12 +- yazi-core/src/tasks/preload.rs | 4 +- yazi-core/src/tasks/process.rs | 15 +- yazi-dds/src/ember/custom.rs | 2 +- yazi-dds/src/sendable.rs | 2 +- yazi-dds/src/spark/spark.rs | 3 + yazi-fm/src/app/commands/accept_payload.rs | 2 +- yazi-fm/src/app/commands/bootstrap.rs | 2 +- yazi-fm/src/app/commands/deprecate.rs | 4 +- yazi-fm/src/app/commands/mouse.rs | 2 +- yazi-fm/src/app/commands/notify.rs | 2 +- yazi-fm/src/app/commands/plugin.rs | 2 +- yazi-fm/src/app/commands/reflow.rs | 2 +- yazi-fm/src/app/commands/render.rs | 2 +- yazi-fm/src/app/commands/resize.rs | 2 +- yazi-fm/src/app/commands/resume.rs | 2 +- yazi-fm/src/app/commands/stop.rs | 2 +- yazi-fm/src/app/commands/update_notify.rs | 2 +- yazi-fm/src/app/commands/update_progress.rs | 2 +- yazi-fm/src/dispatcher.rs | 2 +- yazi-fm/src/executor.rs | 5 +- yazi-fs/src/url.rs | 6 +- yazi-macro/src/event.rs | 4 +- yazi-parser/src/app/deprecate.rs | 8 +- yazi-parser/src/app/plugin.rs | 26 +- yazi-parser/src/arrow.rs | 4 +- yazi-parser/src/cmp/trigger.rs | 2 +- yazi-parser/src/help/toggle.rs | 9 +- yazi-parser/src/input/complete.rs | 2 +- yazi-parser/src/input/kill.rs | 2 +- yazi-parser/src/input/move.rs | 7 +- yazi-parser/src/mgr/cd.rs | 2 +- yazi-parser/src/mgr/copy.rs | 22 +- yazi-parser/src/mgr/download.rs | 20 ++ yazi-parser/src/mgr/escape.rs | 2 +- yazi-parser/src/mgr/filter.rs | 2 +- yazi-parser/src/mgr/find_do.rs | 2 +- yazi-parser/src/mgr/hidden.rs | 2 +- yazi-parser/src/mgr/linemode.rs | 2 +- yazi-parser/src/mgr/mod.rs | 1 + yazi-parser/src/mgr/open.rs | 13 +- yazi-parser/src/mgr/open_do.rs | 6 +- yazi-parser/src/mgr/open_with.rs | 4 +- yazi-parser/src/mgr/peek.rs | 6 +- yazi-parser/src/mgr/quit.rs | 7 +- yazi-parser/src/mgr/rename.rs | 4 +- yazi-parser/src/mgr/reveal.rs | 2 +- yazi-parser/src/mgr/search.rs | 28 +- yazi-parser/src/mgr/seek.rs | 4 +- yazi-parser/src/mgr/shell.rs | 8 +- yazi-parser/src/mgr/sort.rs | 12 +- yazi-parser/src/mgr/spot.rs | 4 +- yazi-parser/src/mgr/tab_close.rs | 4 +- yazi-parser/src/mgr/tab_create.rs | 2 +- yazi-parser/src/mgr/tab_switch.rs | 6 +- yazi-parser/src/mgr/toggle.rs | 8 +- yazi-parser/src/mgr/toggle_all.rs | 16 +- yazi-parser/src/mgr/update_mimes.rs | 4 +- yazi-parser/src/mgr/update_paged.rs | 6 +- yazi-parser/src/notify/tick.rs | 4 +- yazi-parser/src/spot/copy.rs | 2 +- yazi-parser/src/step.rs | 2 +- yazi-parser/src/tasks/process_exec.rs | 4 +- yazi-parser/src/which/callback.rs | 4 +- yazi-plugin/preset/components/current.lua | 2 +- yazi-plugin/preset/plugins/file.lua | 8 +- yazi-plugin/preset/plugins/folder.lua | 2 +- yazi-plugin/preset/plugins/mime-dir.lua | 11 + yazi-plugin/preset/plugins/mime-file.lua | 83 ++++++ yazi-plugin/preset/plugins/mime.lua | 89 +----- yazi-plugin/src/loader/loader.rs | 4 +- yazi-plugin/src/runtime/plugin.rs | 16 +- yazi-plugin/src/utils/sync.rs | 2 +- yazi-proxy/src/tasks.rs | 12 +- yazi-scheduler/src/file/file.rs | 21 +- yazi-scheduler/src/process/in.rs | 8 +- yazi-scheduler/src/process/shell.rs | 12 +- yazi-scheduler/src/scheduler.rs | 37 +++ yazi-shared/src/chars.rs | 2 - yazi-shared/src/data/data.rs | 246 +++++++++++++++++ yazi-shared/src/data/key.rs | 82 ++++++ yazi-shared/src/data/mod.rs | 1 + yazi-shared/src/event/cmd.rs | 126 +++++---- yazi-shared/src/event/cow.rs | 57 ++-- yazi-shared/src/event/data.rs | 276 ------------------- yazi-shared/src/event/mod.rs | 2 +- yazi-shared/src/lib.rs | 2 +- yazi-shared/src/scheme/cow.rs | 2 +- yazi-shared/src/url/cow.rs | 20 +- yazi-shared/src/url/mod.rs | 2 +- yazi-shared/src/url/traits.rs | 20 ++ yazi-vfs/src/fns.rs | 10 +- yazi-vfs/src/provider/sftp/sftp.rs | 8 +- yazi-widgets/src/input/commands/backspace.rs | 2 +- yazi-widgets/src/input/commands/backward.rs | 2 +- yazi-widgets/src/input/commands/commands.rs | 2 +- yazi-widgets/src/input/commands/complete.rs | 2 +- yazi-widgets/src/input/commands/delete.rs | 2 +- yazi-widgets/src/input/commands/escape.rs | 2 +- yazi-widgets/src/input/commands/forward.rs | 2 +- yazi-widgets/src/input/commands/insert.rs | 2 +- yazi-widgets/src/input/commands/kill.rs | 2 +- yazi-widgets/src/input/commands/move.rs | 2 +- yazi-widgets/src/input/commands/paste.rs | 2 +- yazi-widgets/src/input/commands/redo.rs | 2 +- yazi-widgets/src/input/commands/replace.rs | 2 +- yazi-widgets/src/input/commands/type.rs | 2 +- yazi-widgets/src/input/commands/undo.rs | 2 +- yazi-widgets/src/input/commands/visual.rs | 2 +- yazi-widgets/src/input/commands/yank.rs | 2 +- 216 files changed, 1245 insertions(+), 981 deletions(-) create mode 100644 yazi-actor/src/mgr/download.rs create mode 100644 yazi-actor/src/mgr/open_do.rs create mode 100644 yazi-parser/src/mgr/download.rs create mode 100644 yazi-plugin/preset/plugins/mime-dir.lua create mode 100644 yazi-plugin/preset/plugins/mime-file.lua create mode 100644 yazi-shared/src/data/data.rs create mode 100644 yazi-shared/src/data/key.rs create mode 100644 yazi-shared/src/data/mod.rs delete mode 100644 yazi-shared/src/event/data.rs create mode 100644 yazi-shared/src/url/traits.rs diff --git a/README.md b/README.md index 8e309793..d84437a3 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,14 @@ See https://yazi-rs.github.io/docs/image-preview for details. [ueberzug]: https://github.com/jstkdng/ueberzugpp [chafa]: https://hpjansson.org/chafa/ +## Special Thanks + +RustRover logo + +Thanks to RustRover team for providing open-source licenses to support the maintenance of Yazi. + +Active code contributors can contact @sxyazi to get a license (if any are still available). + ## License Yazi is MIT-licensed. For more information check the [LICENSE](LICENSE) file. diff --git a/yazi-actor/src/actor.rs b/yazi-actor/src/actor.rs index b17c90ad..ed8e15ef 100644 --- a/yazi-actor/src/actor.rs +++ b/yazi-actor/src/actor.rs @@ -1,6 +1,6 @@ use anyhow::Result; use yazi_dds::spark::SparkKind; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::Ctx; diff --git a/yazi-actor/src/cmp/arrow.rs b/yazi-actor/src/cmp/arrow.rs index 373719e0..88a868d9 100644 --- a/yazi-actor/src/cmp/arrow.rs +++ b/yazi-actor/src/cmp/arrow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use yazi_widgets::Scrollable; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/cmp/close.rs b/yazi-actor/src/cmp/close.rs index 6551f604..a6c179c3 100644 --- a/yazi-actor/src/cmp/close.rs +++ b/yazi-actor/src/cmp/close.rs @@ -3,7 +3,7 @@ use std::mem; use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::{cmp::CloseOpt, input::CompleteOpt}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/cmp/show.rs b/yazi-actor/src/cmp/show.rs index 43c410a8..99645d87 100644 --- a/yazi-actor/src/cmp/show.rs +++ b/yazi-actor/src/cmp/show.rs @@ -3,7 +3,7 @@ use std::{ffi::OsStr, mem, ops::ControlFlow}; use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::cmp::{CmpItem, ShowOpt}; -use yazi_shared::{event::Data, osstr_contains, osstr_starts_with}; +use yazi_shared::{data::Data, osstr_contains, osstr_starts_with}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/cmp/trigger.rs b/yazi-actor/src/cmp/trigger.rs index 0ca7a0a5..3412e42e 100644 --- a/yazi-actor/src/cmp/trigger.rs +++ b/yazi-actor/src/cmp/trigger.rs @@ -5,7 +5,7 @@ use yazi_fs::{CWD, path::expand_url, provider::{DirReader, FileHolder}}; use yazi_macro::{act, render, succ}; use yazi_parser::cmp::{CmpItem, ShowOpt, TriggerOpt}; use yazi_proxy::CmpProxy; -use yazi_shared::{OsStrSplit, event::Data, natsort, url::{UrlBuf, UrlCow, UrnBuf}}; +use yazi_shared::{OsStrSplit, data::Data, natsort, url::{UrlBuf, UrlCow, UrnBuf}}; use yazi_vfs::provider; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/confirm/arrow.rs b/yazi-actor/src/confirm/arrow.rs index 74e23162..9b0c9f6f 100644 --- a/yazi-actor/src/confirm/arrow.rs +++ b/yazi-actor/src/confirm/arrow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/confirm/close.rs b/yazi-actor/src/confirm/close.rs index 90551b8b..7bc18533 100644 --- a/yazi-actor/src/confirm/close.rs +++ b/yazi-actor/src/confirm/close.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::confirm::CloseOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/confirm/show.rs b/yazi-actor/src/confirm/show.rs index b313d6c1..71be83d9 100644 --- a/yazi-actor/src/confirm/show.rs +++ b/yazi-actor/src/confirm/show.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::confirm::ShowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/context.rs b/yazi-actor/src/context.rs index 9e5446ce..fdae7b95 100644 --- a/yazi-actor/src/context.rs +++ b/yazi-actor/src/context.rs @@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut}; use anyhow::{Result, anyhow}; use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}, tasks::Tasks}; use yazi_fs::File; -use yazi_shared::{Source, event::Cmd, url::UrlBuf}; +use yazi_shared::{Id, Source, event::Cmd, url::UrlBuf}; pub struct Ctx<'a> { pub core: &'a mut Core, @@ -25,7 +25,7 @@ impl DerefMut for Ctx<'_> { impl<'a> Ctx<'a> { #[inline] pub fn new(core: &'a mut Core, cmd: &Cmd) -> Result { - let tab = if let Some(id) = cmd.id("tab") { + let tab = if let Ok(id) = cmd.get::("tab") { core .mgr .tabs diff --git a/yazi-actor/src/help/arrow.rs b/yazi-actor/src/help/arrow.rs index fc2412b0..495e612d 100644 --- a/yazi-actor/src/help/arrow.rs +++ b/yazi-actor/src/help/arrow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use yazi_widgets::Scrollable; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/help/escape.rs b/yazi-actor/src/help/escape.rs index 041b50f3..d45b1802 100644 --- a/yazi-actor/src/help/escape.rs +++ b/yazi-actor/src/help/escape.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/help/filter.rs b/yazi-actor/src/help/filter.rs index d20d2f72..f82c7c70 100644 --- a/yazi-actor/src/help/filter.rs +++ b/yazi-actor/src/help/filter.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/help/toggle.rs b/yazi-actor/src/help/toggle.rs index a2c90d52..37074dec 100644 --- a/yazi-actor/src/help/toggle.rs +++ b/yazi-actor/src/help/toggle.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::help::ToggleOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/input/close.rs b/yazi-actor/src/input/close.rs index a63097ab..f0261468 100644 --- a/yazi-actor/src/input/close.rs +++ b/yazi-actor/src/input/close.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::input::CloseOpt; -use yazi_shared::{errors::InputError, event::Data}; +use yazi_shared::{data::Data, errors::InputError}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/input/escape.rs b/yazi-actor/src/input/escape.rs index 1d84d0d9..0bde71e9 100644 --- a/yazi-actor/src/input/escape.rs +++ b/yazi-actor/src/input/escape.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use yazi_widgets::input::InputOp; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/input/show.rs b/yazi-actor/src/input/show.rs index b18a37e0..c498c7f2 100644 --- a/yazi-actor/src/input/show.rs +++ b/yazi-actor/src/input/show.rs @@ -4,7 +4,7 @@ use anyhow::Result; use yazi_config::YAZI; use yazi_macro::{act, render, succ}; use yazi_parser::input::ShowOpt; -use yazi_shared::{errors::InputError, event::Data}; +use yazi_shared::{data::Data, errors::InputError}; use yazi_widgets::input::InputCallback; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/lives/file.rs b/yazi-actor/src/lives/file.rs index ab731a0d..8bd20e9d 100644 --- a/yazi-actor/src/lives/file.rs +++ b/yazi-actor/src/lives/file.rs @@ -80,7 +80,7 @@ impl UserData for File { }); methods.add_method("mime", |lua, me, ()| { lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { - core.mgr.mimetype.by_url(&me.url).map(|s| lua.create_string(s)).transpose() + core.mgr.mimetype.get(&me.url).map(|s| lua.create_string(s)).transpose() })? }); methods.add_method("prefix", |lua, me, ()| { @@ -97,7 +97,7 @@ impl UserData for File { }); methods.add_method("style", |lua, me, ()| { lua.named_registry_value::("cx")?.borrow_scoped(|core: &yazi_core::Core| { - let mime = core.mgr.mimetype.by_file(me).unwrap_or_default(); + let mime = core.mgr.mimetype.get(&me.url).unwrap_or_default(); THEME.filetype.iter().find(|&x| x.matches(me, mime)).map(|x| Style::from(x.style)) }) }); diff --git a/yazi-actor/src/mgr/arrow.rs b/yazi-actor/src/mgr/arrow.rs index b2b3b71c..c2be4481 100644 --- a/yazi-actor/src/mgr/arrow.rs +++ b/yazi-actor/src/mgr/arrow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/back.rs b/yazi-actor/src/mgr/back.rs index c6332deb..95f744f3 100644 --- a/yazi-actor/src/mgr/back.rs +++ b/yazi-actor/src/mgr/back.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::{VoidOpt, mgr::CdSource}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/bulk_rename.rs b/yazi-actor/src/mgr/bulk_rename.rs index dc135e72..c63491df 100644 --- a/yazi-actor/src/mgr/bulk_rename.rs +++ b/yazi-actor/src/mgr/bulk_rename.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, ffi::{OsStr, OsString}, hash::Hash, io::{Read, Write}, ops::Deref, path::Path}; +use std::{borrow::Cow, ffi::{OsStr, OsString}, hash::Hash, io::{Read, Write}, ops::Deref}; use anyhow::{Result, anyhow}; use crossterm::{execute, style::Print}; @@ -11,7 +11,7 @@ use yazi_fs::{File, FilesOp, max_common_root, path::skip_url, provider::{FileBui use yazi_macro::{err, succ}; use yazi_parser::VoidOpt; use yazi_proxy::{AppProxy, HIDER, TasksProxy}; -use yazi_shared::{OsStrJoin, event::Data, terminal_clear, url::{Component, UrlBuf}}; +use yazi_shared::{OsStrJoin, data::Data, terminal_clear, url::{Component, Url, UrlBuf}}; use yazi_term::tty::TTY; use yazi_vfs::{VfsFile, maybe_exists, provider}; use yazi_watcher::WATCHER; @@ -52,8 +52,8 @@ impl Actor for BulkRename { defer! { tokio::spawn(Local.remove_file(tmp.clone())); } TasksProxy::process_exec(Cow::Borrowed(opener), cwd, vec![ - OsString::new(), - tmp.to_owned().into(), + OsStr::new("").into(), + tmp.as_os_str().to_owned().into(), ]) .await; @@ -147,7 +147,7 @@ impl BulkRename { } fn opener() -> Option<&'static OpenerRule> { - YAZI.opener.block(YAZI.open.all(UrlBuf::from(Path::new("bulk-rename.txt")), "text/plain")) + YAZI.opener.block(YAZI.open.all(Url::regular("bulk-rename.txt"), "text/plain")) } async fn output_failed(failed: Vec<(Tuple, Tuple, anyhow::Error)>) -> Result<()> { diff --git a/yazi-actor/src/mgr/cd.rs b/yazi-actor/src/mgr/cd.rs index 5a7031b0..8a4118f2 100644 --- a/yazi-actor/src/mgr/cd.rs +++ b/yazi-actor/src/mgr/cd.rs @@ -9,7 +9,7 @@ use yazi_fs::{File, FilesOp, path::expand_url}; use yazi_macro::{act, err, render, succ}; use yazi_parser::mgr::CdOpt; use yazi_proxy::{CmpProxy, InputProxy, MgrProxy}; -use yazi_shared::{Debounce, errors::InputError, event::Data, url::UrlBuf}; +use yazi_shared::{Debounce, data::Data, errors::InputError, url::UrlBuf}; use yazi_vfs::VfsFile; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/close.rs b/yazi-actor/src/mgr/close.rs index e2a6bd50..2e0620b2 100644 --- a/yazi-actor/src/mgr/close.rs +++ b/yazi-actor/src/mgr/close.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::act; use yazi_parser::mgr::CloseOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/copy.rs b/yazi-actor/src/mgr/copy.rs index 9c6c2e3e..05baac1b 100644 --- a/yazi-actor/src/mgr/copy.rs +++ b/yazi-actor/src/mgr/copy.rs @@ -3,7 +3,7 @@ use std::ffi::OsString; use anyhow::{Result, bail}; use yazi_macro::{act, succ}; use yazi_parser::mgr::CopyOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use yazi_widgets::CLIPBOARD; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/create.rs b/yazi-actor/src/mgr/create.rs index c14c3077..51c57d1f 100644 --- a/yazi-actor/src/mgr/create.rs +++ b/yazi-actor/src/mgr/create.rs @@ -1,10 +1,10 @@ use anyhow::{Result, bail}; use yazi_config::popup::{ConfirmCfg, InputCfg}; -use yazi_fs::{File, FilesOp, ok_or_not_found}; -use yazi_macro::succ; +use yazi_fs::{File, FilesOp}; +use yazi_macro::{ok_or_not_found, succ}; use yazi_parser::mgr::CreateOpt; use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy}; -use yazi_shared::{event::Data, url::UrlBuf}; +use yazi_shared::{data::Data, url::UrlBuf}; use yazi_vfs::{VfsFile, maybe_exists, provider}; use yazi_watcher::WATCHER; @@ -50,12 +50,12 @@ impl Create { } else if let Ok(real) = provider::casefold(&new).await && let Some((parent, urn)) = real.pair() { - ok_or_not_found(provider::remove_file(&new).await)?; + ok_or_not_found!(provider::remove_file(&new).await); FilesOp::Deleting(parent.into(), [urn.into()].into()).emit(); provider::create(&new).await?; } else if let Some(parent) = new.parent() { provider::create_dir_all(parent).await.ok(); - ok_or_not_found(provider::remove_file(&new).await)?; + ok_or_not_found!(provider::remove_file(&new).await); provider::create(&new).await?; } else { bail!("Cannot create file at root"); diff --git a/yazi-actor/src/mgr/download.rs b/yazi-actor/src/mgr/download.rs new file mode 100644 index 00000000..d57dcce2 --- /dev/null +++ b/yazi-actor/src/mgr/download.rs @@ -0,0 +1,58 @@ +use std::{mem, time::{Duration, Instant}}; + +use anyhow::Result; +use futures::{StreamExt, stream::FuturesUnordered}; +use tokio::sync::oneshot; +use yazi_fs::File; +use yazi_macro::{act, succ}; +use yazi_parser::mgr::DownloadOpt; +use yazi_shared::data::Data; +use yazi_vfs::VfsFile; + +use crate::{Actor, Ctx}; + +pub struct Download; + +impl Actor for Download { + type Options = DownloadOpt; + + const NAME: &str = "download"; + + fn act(cx: &mut Ctx, opt: Self::Options) -> Result { + act!(mgr:escape_visual, cx)?; + + let mut wg1 = FuturesUnordered::new(); + for url in opt.urls { + let (tx, rx) = oneshot::channel(); + cx.tasks.scheduler.file_download(url.to_owned(), Some(tx)); + wg1.push(async move { (rx.await == Ok(true), url) }); + } + + let scheduler = cx.tasks.scheduler.clone(); + tokio::spawn(async move { + let mut wg2 = vec![]; + let mut files = Vec::with_capacity(wg1.len()); + let mut instant = Instant::now(); + while let Some((success, url)) = wg1.next().await { + if !success { + continue; + } + + let Ok(f) = File::new(url).await else { continue }; + files.push(f); + + if instant.elapsed() >= Duration::from_secs(1) { + wg2.push(scheduler.fetch_mimetype(mem::take(&mut files))); + instant = Instant::now(); + } + } + + if !files.is_empty() { + wg2.push(scheduler.fetch_mimetype(files)); + } + futures::future::join_all(wg2).await; + }); + + succ!(); + } +} diff --git a/yazi-actor/src/mgr/enter.rs b/yazi-actor/src/mgr/enter.rs index 7fd43280..efece673 100644 --- a/yazi-actor/src/mgr/enter.rs +++ b/yazi-actor/src/mgr/enter.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::{VoidOpt, mgr::CdSource}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/escape.rs b/yazi-actor/src/mgr/escape.rs index d6c9a349..aee89094 100644 --- a/yazi-actor/src/mgr/escape.rs +++ b/yazi-actor/src/mgr/escape.rs @@ -2,7 +2,7 @@ use anyhow::{Result, bail}; use yazi_macro::{act, render, render_and, succ}; use yazi_parser::{VoidOpt, mgr::EscapeOpt}; use yazi_proxy::AppProxy; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/filter.rs b/yazi-actor/src/mgr/filter.rs index e09a5fda..c229588a 100644 --- a/yazi-actor/src/mgr/filter.rs +++ b/yazi-actor/src/mgr/filter.rs @@ -7,7 +7,7 @@ use yazi_config::popup::InputCfg; use yazi_macro::succ; use yazi_parser::mgr::FilterOpt; use yazi_proxy::{InputProxy, MgrProxy}; -use yazi_shared::{Debounce, errors::InputError, event::Data}; +use yazi_shared::{Debounce, data::Data, errors::InputError}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/filter_do.rs b/yazi-actor/src/mgr/filter_do.rs index c68fc4da..d5de8094 100644 --- a/yazi-actor/src/mgr/filter_do.rs +++ b/yazi-actor/src/mgr/filter_do.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_fs::Filter; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::FilterOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/find.rs b/yazi-actor/src/mgr/find.rs index bd663090..6e8bc916 100644 --- a/yazi-actor/src/mgr/find.rs +++ b/yazi-actor/src/mgr/find.rs @@ -7,7 +7,7 @@ use yazi_config::popup::InputCfg; use yazi_macro::succ; use yazi_parser::mgr::{FindDoOpt, FindOpt}; use yazi_proxy::{InputProxy, MgrProxy}; -use yazi_shared::{Debounce, errors::InputError, event::Data}; +use yazi_shared::{Debounce, data::Data, errors::InputError}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/find_arrow.rs b/yazi-actor/src/mgr/find_arrow.rs index 6bdbd0b8..7ef3067a 100644 --- a/yazi-actor/src/mgr/find_arrow.rs +++ b/yazi-actor/src/mgr/find_arrow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::FindArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/find_do.rs b/yazi-actor/src/mgr/find_do.rs index c4d75d0b..296c09f6 100644 --- a/yazi-actor/src/mgr/find_do.rs +++ b/yazi-actor/src/mgr/find_do.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_core::tab::Finder; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::FindDoOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/follow.rs b/yazi-actor/src/mgr/follow.rs index 8802b6d2..36817809 100644 --- a/yazi-actor/src/mgr/follow.rs +++ b/yazi-actor/src/mgr/follow.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_fs::path::clean_url; use yazi_macro::{act, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/forward.rs b/yazi-actor/src/mgr/forward.rs index de572e74..a6642df5 100644 --- a/yazi-actor/src/mgr/forward.rs +++ b/yazi-actor/src/mgr/forward.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::{VoidOpt, mgr::CdSource}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/hardlink.rs b/yazi-actor/src/mgr/hardlink.rs index 1c51ec5c..59006581 100644 --- a/yazi-actor/src/mgr/hardlink.rs +++ b/yazi-actor/src/mgr/hardlink.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::mgr::HardlinkOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/hidden.rs b/yazi-actor/src/mgr/hidden.rs index fc44e3d5..efc55f03 100644 --- a/yazi-actor/src/mgr/hidden.rs +++ b/yazi-actor/src/mgr/hidden.rs @@ -3,7 +3,7 @@ use yazi_core::tab::Folder; use yazi_fs::FolderStage; use yazi_macro::{act, render, render_and, succ}; use yazi_parser::mgr::HiddenOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/hover.rs b/yazi-actor/src/mgr/hover.rs index f4eb1d2f..ea6c1440 100644 --- a/yazi-actor/src/mgr/hover.rs +++ b/yazi-actor/src/mgr/hover.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_dds::Pubsub; use yazi_macro::{err, render, succ, tab}; use yazi_parser::mgr::HoverOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/leave.rs b/yazi-actor/src/mgr/leave.rs index 4c1935d8..a7324850 100644 --- a/yazi-actor/src/mgr/leave.rs +++ b/yazi-actor/src/mgr/leave.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::{VoidOpt, mgr::CdSource}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/linemode.rs b/yazi-actor/src/mgr/linemode.rs index c5a23b52..3cd6dc91 100644 --- a/yazi-actor/src/mgr/linemode.rs +++ b/yazi-actor/src/mgr/linemode.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::mgr::LinemodeOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/link.rs b/yazi-actor/src/mgr/link.rs index cc86dce2..868489a7 100644 --- a/yazi-actor/src/mgr/link.rs +++ b/yazi-actor/src/mgr/link.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::mgr::LinkOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/mod.rs b/yazi-actor/src/mgr/mod.rs index 88ff46c4..49f9b3d4 100644 --- a/yazi-actor/src/mgr/mod.rs +++ b/yazi-actor/src/mgr/mod.rs @@ -6,6 +6,7 @@ yazi_macro::mod_flat!( close copy create + download enter escape filter @@ -22,6 +23,7 @@ yazi_macro::mod_flat!( linemode link open + open_do paste peek quit diff --git a/yazi-actor/src/mgr/open.rs b/yazi-actor/src/mgr/open.rs index 3013ca26..6a7d6668 100644 --- a/yazi-actor/src/mgr/open.rs +++ b/yazi-actor/src/mgr/open.rs @@ -1,14 +1,10 @@ -use std::{borrow::Cow, iter}; - use anyhow::Result; -use tokio::sync::oneshot; -use yazi_config::{YAZI, popup::PickCfg}; -use yazi_core::tab::Folder; +use yazi_boot::ARGS; use yazi_fs::File; use yazi_macro::{act, succ}; use yazi_parser::mgr::{OpenDoOpt, OpenOpt}; -use yazi_proxy::{MgrProxy, PickProxy, TasksProxy}; -use yazi_shared::{MIME_DIR, event::Data, url::UrlBuf}; +use yazi_proxy::MgrProxy; +use yazi_shared::{data::Data, url::UrlCow}; use yazi_vfs::VfsFile; use crate::{Actor, Ctx, mgr::Quit}; @@ -20,118 +16,59 @@ impl Actor for Open { const NAME: &str = "open"; - fn act(cx: &mut Ctx, opt: Self::Options) -> Result { + fn act(cx: &mut Ctx, mut opt: Self::Options) -> Result { act!(mgr:escape_visual, cx)?; - let Some(hovered) = cx.hovered().map(|h| h.url_owned()) else { succ!() }; + let Some(hovered) = cx.hovered().map(|h| h.url_owned()).map(UrlCow::from) else { succ!() }; - let mut selected = - if opt.hovered { Box::new(iter::once(&hovered)) } else { cx.tab().selected_or_hovered() }; - if Quit::quit_with_selected(opt, &mut selected) { - succ!(); + if !opt.interactive && ARGS.chooser_file.is_some() { + succ!(if !opt.targets.is_empty() { + Quit::with_selected(opt.targets) + } else if opt.hovered { + Quit::with_selected([hovered]) + } else { + Quit::with_selected(cx.tab().selected_or_hovered()) + }); } - let mut todo = vec![]; - let targets: Vec<_> = selected - .cloned() + if opt.targets.is_empty() { + opt.targets = if opt.hovered { + vec![hovered.clone()] + } else { + cx.tab().selected_or_hovered().cloned().map(Into::into).collect() + }; + } + + let todo: Vec<_> = opt + .targets + .iter() .enumerate() - .map(|(i, u)| { - if cx.mgr.mimetype.contains(&u) { - (u, "") - } else if Self::guess_folder(cx, &u) { - (u, MIME_DIR) - } else { - todo.push(i); - (u, "") - } - }) + .filter(|&(_, u)| !cx.mgr.mimetype.contains(u)) + .map(|(i, _)| i) .collect(); let cwd = cx.cwd().clone(); if todo.is_empty() { - return act!(mgr:open_do, cx, OpenDoOpt { cwd, hovered, targets, interactive: opt.interactive }); + return act!(mgr:open_do, cx, OpenDoOpt { cwd, hovered, targets: opt.targets, interactive: opt.interactive }); } let scheduler = cx.tasks.scheduler.clone(); tokio::spawn(async move { let mut files = Vec::with_capacity(todo.len()); for i in todo { - if let Ok(f) = File::new(&targets[i].0).await { + if let Ok(f) = File::new(&opt.targets[i]).await { files.push(f); } } - - let mut wg = vec![]; - for (fetcher, files) in YAZI.plugin.mime_fetchers(files) { - let (tx, rx) = oneshot::channel(); - scheduler.fetch_paged(fetcher, files, Some(tx)); - wg.push(rx); - } - - for rx in wg { - if !rx.await.is_ok_and(|canceled| !canceled) { - return; - } - } - - MgrProxy::open_do(OpenDoOpt { cwd, hovered, targets, interactive: opt.interactive }); - }); - succ!(); - } -} - -// --- Do -pub struct OpenDo; - -impl Actor for OpenDo { - type Options = OpenDoOpt; - - const NAME: &str = "open_do"; - - fn act(cx: &mut Ctx, opt: Self::Options) -> Result { - let mut targets = opt.targets; - targets.iter_mut().filter(|(_, m)| m.is_empty()).for_each(|(u, m)| { - *m = cx.mgr.mimetype.by_url(u).unwrap_or_default(); - }); - - targets.retain(|(_, m)| !m.is_empty()); - if targets.is_empty() { - succ!(); - } else if !opt.interactive { - succ!(cx.tasks.process_from_files(opt.cwd, opt.hovered, targets)); - } - - let openers: Vec<_> = YAZI.opener.all(YAZI.open.common(&targets).into_iter()); - if openers.is_empty() { - succ!(); - } - - let pick = PickProxy::show(PickCfg::open(openers.iter().map(|o| o.desc()).collect())); - let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect(); - tokio::spawn(async move { - if let Ok(choice) = pick.await { - TasksProxy::open_with(Cow::Borrowed(openers[choice]), opt.cwd, urls); + if scheduler.fetch_mimetype(files).await { + MgrProxy::open_do(OpenDoOpt { + cwd, + hovered, + targets: opt.targets, + interactive: opt.interactive, + }); } }); succ!(); } } - -impl Open { - fn guess_folder(cx: &Ctx, url: &UrlBuf) -> bool { - let Some(p) = url.parent() else { - return true; - }; - - let find = |folder: Option<&Folder>| { - folder.is_some_and(|folder| { - p == folder.url && folder.files.iter().any(|f| f.is_dir() && f.urn() == url.urn()) - }) - }; - - find(Some(cx.current())) - || find(cx.parent()) - || find(cx.hovered_folder()) - || find(cx.tab().history.get(&p)) - } -} diff --git a/yazi-actor/src/mgr/open_do.rs b/yazi-actor/src/mgr/open_do.rs new file mode 100644 index 00000000..a3575b15 --- /dev/null +++ b/yazi-actor/src/mgr/open_do.rs @@ -0,0 +1,50 @@ +use std::borrow::Cow; + +use anyhow::Result; +use yazi_config::{YAZI, popup::PickCfg}; +use yazi_macro::succ; +use yazi_parser::mgr::OpenDoOpt; +use yazi_proxy::{PickProxy, TasksProxy}; +use yazi_shared::data::Data; + +use crate::{Actor, Ctx}; + +pub struct OpenDo; + +impl Actor for OpenDo { + type Options = OpenDoOpt; + + const NAME: &str = "open_do"; + + fn act(cx: &mut Ctx, opt: Self::Options) -> Result { + let targets: Vec<_> = opt + .targets + .into_iter() + .map(|u| { + let m = cx.mgr.mimetype.get(&u).unwrap_or_default(); + (u, m) + }) + .filter(|(_, m)| !m.is_empty()) + .collect(); + + if targets.is_empty() { + succ!(); + } else if !opt.interactive { + succ!(cx.tasks.process_from_files(opt.cwd, opt.hovered, targets)); + } + + let openers: Vec<_> = YAZI.opener.all(YAZI.open.common(&targets).into_iter()); + if openers.is_empty() { + succ!(); + } + + let pick = PickProxy::show(PickCfg::open(openers.iter().map(|o| o.desc()).collect())); + let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect(); + tokio::spawn(async move { + if let Ok(choice) = pick.await { + TasksProxy::open_with(Cow::Borrowed(openers[choice]), opt.cwd, urls); + } + }); + succ!(); + } +} diff --git a/yazi-actor/src/mgr/paste.rs b/yazi-actor/src/mgr/paste.rs index a53eeffb..7cfc647a 100644 --- a/yazi-actor/src/mgr/paste.rs +++ b/yazi-actor/src/mgr/paste.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::mgr::PasteOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/peek.rs b/yazi-actor/src/mgr/peek.rs index f9f2f83a..3940cd82 100644 --- a/yazi-actor/src/mgr/peek.rs +++ b/yazi-actor/src/mgr/peek.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::mgr::PeekOpt; use yazi_proxy::HIDER; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; @@ -21,7 +21,7 @@ impl Actor for Peek { succ!(cx.tab_mut().preview.reset_image()); } - let mime = cx.mgr.mimetype.by_file_owned(&hovered).unwrap_or_default(); + let mime = cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default(); let folder = cx.tab().hovered_folder().map(|f| (f.offset, f.cha)); if !cx.tab().preview.same_url(&hovered.url) { diff --git a/yazi-actor/src/mgr/quit.rs b/yazi-actor/src/mgr/quit.rs index 6d71b2e9..fc1a2a57 100644 --- a/yazi-actor/src/mgr/quit.rs +++ b/yazi-actor/src/mgr/quit.rs @@ -2,13 +2,12 @@ use std::{ffi::OsString, time::Duration}; use anyhow::Result; use tokio::{select, time}; -use yazi_boot::ARGS; use yazi_config::popup::ConfirmCfg; use yazi_dds::spark::SparkKind; use yazi_macro::{emit, succ}; -use yazi_parser::mgr::{OpenOpt, QuitOpt}; +use yazi_parser::mgr::QuitOpt; use yazi_proxy::ConfirmProxy; -use yazi_shared::{event::{Data, EventQuit}, url::UrlBuf}; +use yazi_shared::{data::Data, event::EventQuit, url::UrlCow}; use crate::{Actor, Ctx}; @@ -67,21 +66,17 @@ impl Actor for Quit { } impl Quit { - pub(super) fn quit_with_selected<'a, I>(opt: OpenOpt, selected: I) -> bool + pub(super) fn with_selected<'a, I, T>(selected: I) where - I: Iterator, + I: IntoIterator, + T: Into>, { - if opt.interactive || ARGS.chooser_file.is_none() { - return false; - } - - let paths = selected.fold(OsString::new(), |mut s, u| { - s.push(u.os_str()); + let paths = selected.into_iter().fold(OsString::new(), |mut s, u| { + s.push(u.into().as_url().os_str()); s.push("\n"); s }); emit!(Quit(EventQuit { selected: Some(paths), ..Default::default() })); - true } } diff --git a/yazi-actor/src/mgr/refresh.rs b/yazi-actor/src/mgr/refresh.rs index dca99f50..f5632716 100644 --- a/yazi-actor/src/mgr/refresh.rs +++ b/yazi-actor/src/mgr/refresh.rs @@ -5,7 +5,7 @@ use yazi_core::tab::Folder; use yazi_fs::{CWD, Files, FilesOp, cha::Cha}; use yazi_macro::{act, succ}; use yazi_parser::VoidOpt; -use yazi_shared::{event::Data, url::UrlBuf}; +use yazi_shared::{data::Data, url::UrlBuf}; use yazi_term::tty::TTY; use yazi_vfs::{VfsFiles, VfsFilesOp}; diff --git a/yazi-actor/src/mgr/remove.rs b/yazi-actor/src/mgr/remove.rs index 23fb1d37..ee69f344 100644 --- a/yazi-actor/src/mgr/remove.rs +++ b/yazi-actor/src/mgr/remove.rs @@ -3,7 +3,7 @@ use yazi_config::popup::ConfirmCfg; use yazi_macro::{act, succ}; use yazi_parser::mgr::RemoveOpt; use yazi_proxy::{ConfirmProxy, MgrProxy}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/rename.rs b/yazi-actor/src/mgr/rename.rs index fcd2da14..959385d1 100644 --- a/yazi-actor/src/mgr/rename.rs +++ b/yazi-actor/src/mgr/rename.rs @@ -1,11 +1,11 @@ use anyhow::Result; use yazi_config::popup::{ConfirmCfg, InputCfg}; use yazi_dds::Pubsub; -use yazi_fs::{File, FilesOp, ok_or_not_found}; -use yazi_macro::{act, err, succ}; +use yazi_fs::{File, FilesOp}; +use yazi_macro::{act, err, ok_or_not_found, succ}; use yazi_parser::mgr::RenameOpt; use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy}; -use yazi_shared::{Id, event::Data, url::UrlBuf}; +use yazi_shared::{Id, data::Data, url::UrlBuf}; use yazi_vfs::{VfsFile, maybe_exists, provider}; use yazi_watcher::WATCHER; @@ -72,7 +72,7 @@ impl Rename { if let Ok(u) = overwritten && let Some((parent, urn)) = u.pair() { - ok_or_not_found(provider::rename(&u, &new).await)?; + ok_or_not_found!(provider::rename(&u, &new).await); FilesOp::Deleting(parent.to_owned(), [urn.into()].into()).emit(); } diff --git a/yazi-actor/src/mgr/reveal.rs b/yazi-actor/src/mgr/reveal.rs index c95d414b..1c148b73 100644 --- a/yazi-actor/src/mgr/reveal.rs +++ b/yazi-actor/src/mgr/reveal.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_fs::{File, FilesOp}; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::RevealOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/search.rs b/yazi-actor/src/mgr/search.rs index 33bd30ea..2b576afa 100644 --- a/yazi-actor/src/mgr/search.rs +++ b/yazi-actor/src/mgr/search.rs @@ -9,7 +9,7 @@ use yazi_macro::{act, succ}; use yazi_parser::{VoidOpt, mgr::{SearchOpt, SearchOptVia}}; use yazi_plugin::external; use yazi_proxy::{InputProxy, MgrProxy}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/seek.rs b/yazi-actor/src/mgr/seek.rs index 25fdbc78..dc1f13f5 100644 --- a/yazi-actor/src/mgr/seek.rs +++ b/yazi-actor/src/mgr/seek.rs @@ -3,7 +3,7 @@ use yazi_config::YAZI; use yazi_macro::succ; use yazi_parser::mgr::SeekOpt; use yazi_plugin::isolate; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; @@ -19,11 +19,11 @@ impl Actor for Seek { succ!(cx.tab_mut().preview.reset()); }; - let Some(mime) = cx.mgr.mimetype.by_file(hovered) else { + let Some(mime) = cx.mgr.mimetype.get(&hovered.url) else { succ!(cx.tab_mut().preview.reset()); }; - let Some(previewer) = YAZI.plugin.previewer(&hovered.url, mime) else { + let Some(previewer) = YAZI.plugin.previewer(hovered, mime) else { succ!(cx.tab_mut().preview.reset()); }; diff --git a/yazi-actor/src/mgr/shell.rs b/yazi-actor/src/mgr/shell.rs index 1bbf900b..9b04fcfa 100644 --- a/yazi-actor/src/mgr/shell.rs +++ b/yazi-actor/src/mgr/shell.rs @@ -5,7 +5,7 @@ use yazi_config::{opener::OpenerRule, popup::InputCfg}; use yazi_macro::{act, succ}; use yazi_parser::mgr::ShellOpt; use yazi_proxy::{InputProxy, TasksProxy}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; @@ -20,7 +20,7 @@ impl Actor for Shell { act!(mgr:escape_visual, cx)?; let cwd = opt.cwd.take().unwrap_or(cx.cwd().into()).into_owned(); - let selected = cx.tab().hovered_and_selected().cloned().collect(); + let selected = cx.tab().hovered_and_selected().cloned().map(Into::into).collect(); let input = opt.interactive.then(|| { InputProxy::show(InputCfg::shell(opt.block).with_value(&*opt.run).with_cursor(opt.cursor)) diff --git a/yazi-actor/src/mgr/sort.rs b/yazi-actor/src/mgr/sort.rs index b5f55f8a..f0348b01 100644 --- a/yazi-actor/src/mgr/sort.rs +++ b/yazi-actor/src/mgr/sort.rs @@ -3,7 +3,7 @@ use yazi_core::tab::Folder; use yazi_fs::{FilesSorter, FolderStage}; use yazi_macro::{act, render, render_and, succ}; use yazi_parser::mgr::SortOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/spot.rs b/yazi-actor/src/mgr/spot.rs index 7fbedbc8..eafe6e69 100644 --- a/yazi-actor/src/mgr/spot.rs +++ b/yazi-actor/src/mgr/spot.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::mgr::SpotOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; @@ -15,7 +15,7 @@ impl Actor for Spot { fn act(cx: &mut Ctx, opt: Self::Options) -> Result { let Some(hovered) = cx.hovered().cloned() else { succ!() }; - let mime = cx.mgr.mimetype.by_file_owned(&hovered).unwrap_or_default(); + let mime = cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default(); // if !self.active().spot.same_file(&hovered, &mime) { // self.active_mut().spot.reset(); // } diff --git a/yazi-actor/src/mgr/suspend.rs b/yazi-actor/src/mgr/suspend.rs index 61da21fb..b34eac63 100644 --- a/yazi-actor/src/mgr/suspend.rs +++ b/yazi-actor/src/mgr/suspend.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/tab_close.rs b/yazi-actor/src/mgr/tab_close.rs index 2a0b9efb..23dde947 100644 --- a/yazi-actor/src/mgr/tab_close.rs +++ b/yazi-actor/src/mgr/tab_close.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::TabCloseOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/tab_create.rs b/yazi-actor/src/mgr/tab_create.rs index 5d9d4af8..9ddbcea9 100644 --- a/yazi-actor/src/mgr/tab_create.rs +++ b/yazi-actor/src/mgr/tab_create.rs @@ -3,7 +3,7 @@ use yazi_core::tab::Tab; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::{CdSource, TabCreateOpt}; use yazi_proxy::AppProxy; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/tab_swap.rs b/yazi-actor/src/mgr/tab_swap.rs index 8f728946..6b4eaed2 100644 --- a/yazi-actor/src/mgr/tab_swap.rs +++ b/yazi-actor/src/mgr/tab_swap.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_dds::Pubsub; use yazi_macro::{err, render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/tab_switch.rs b/yazi-actor/src/mgr/tab_switch.rs index 0ff7ef29..bf86e002 100644 --- a/yazi-actor/src/mgr/tab_switch.rs +++ b/yazi-actor/src/mgr/tab_switch.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::TabSwitchOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/toggle.rs b/yazi-actor/src/mgr/toggle.rs index ef7fd091..153b2296 100644 --- a/yazi-actor/src/mgr/toggle.rs +++ b/yazi-actor/src/mgr/toggle.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_macro::{render_and, succ}; use yazi_parser::mgr::ToggleOpt; use yazi_proxy::AppProxy; -use yazi_shared::{event::Data, url::UrlCow}; +use yazi_shared::{data::Data, url::UrlCow}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/toggle_all.rs b/yazi-actor/src/mgr/toggle_all.rs index 80dbc889..54ea0e0d 100644 --- a/yazi-actor/src/mgr/toggle_all.rs +++ b/yazi-actor/src/mgr/toggle_all.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::mgr::ToggleAllOpt; use yazi_proxy::AppProxy; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/unyank.rs b/yazi-actor/src/mgr/unyank.rs index 4a896798..21f66e18 100644 --- a/yazi-actor/src/mgr/unyank.rs +++ b/yazi-actor/src/mgr/unyank.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::Actor; diff --git a/yazi-actor/src/mgr/update_files.rs b/yazi-actor/src/mgr/update_files.rs index d2219931..d4b7e5f6 100644 --- a/yazi-actor/src/mgr/update_files.rs +++ b/yazi-actor/src/mgr/update_files.rs @@ -3,7 +3,7 @@ use yazi_core::tab::Folder; use yazi_fs::FilesOp; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::UpdateFilesOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use yazi_watcher::LINKED; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/update_mimes.rs b/yazi-actor/src/mgr/update_mimes.rs index aa44454f..181f820d 100644 --- a/yazi-actor/src/mgr/update_mimes.rs +++ b/yazi-actor/src/mgr/update_mimes.rs @@ -2,7 +2,7 @@ use anyhow::Result; use hashbrown::HashMap; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::UpdateMimesOpt; -use yazi_shared::{event::Data, pool::InternStr, url::UrlCov}; +use yazi_shared::{data::Data, pool::InternStr, url::UrlCov}; use yazi_watcher::LINKED; use crate::{Actor, Ctx}; @@ -20,7 +20,7 @@ impl Actor for UpdateMimes { .updates .into_iter() .flat_map(|(key, value)| key.into_url().zip(value.into_string())) - .filter(|(url, mime)| cx.mgr.mimetype.by_url(url) != Some(mime)) + .filter(|(url, mime)| cx.mgr.mimetype.get(url) != Some(mime)) .fold(HashMap::new(), |mut map, (u, m)| { for u in linked.from_file(u.as_url()) { map.insert(u.into(), m.intern()); diff --git a/yazi-actor/src/mgr/update_paged.rs b/yazi-actor/src/mgr/update_paged.rs index 3b0fdbb1..90d501b3 100644 --- a/yazi-actor/src/mgr/update_paged.rs +++ b/yazi-actor/src/mgr/update_paged.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::mgr::UpdatePagedOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/update_peeked.rs b/yazi-actor/src/mgr/update_peeked.rs index 6d3a5867..0fa01a6b 100644 --- a/yazi-actor/src/mgr/update_peeked.rs +++ b/yazi-actor/src/mgr/update_peeked.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::mgr::UpdatePeekedOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::Actor; diff --git a/yazi-actor/src/mgr/update_spotted.rs b/yazi-actor/src/mgr/update_spotted.rs index ad393ab5..9c15d0cc 100644 --- a/yazi-actor/src/mgr/update_spotted.rs +++ b/yazi-actor/src/mgr/update_spotted.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::mgr::UpdateSpottedOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/update_yanked.rs b/yazi-actor/src/mgr/update_yanked.rs index 8f45e326..2b3120e9 100644 --- a/yazi-actor/src/mgr/update_yanked.rs +++ b/yazi-actor/src/mgr/update_yanked.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_core::mgr::Yanked; use yazi_macro::{render, succ}; use yazi_parser::mgr::UpdateYankedOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/visual_mode.rs b/yazi-actor/src/mgr/visual_mode.rs index c71c8f62..e805a96f 100644 --- a/yazi-actor/src/mgr/visual_mode.rs +++ b/yazi-actor/src/mgr/visual_mode.rs @@ -4,7 +4,7 @@ use anyhow::Result; use yazi_core::tab::Mode; use yazi_macro::{render, succ}; use yazi_parser::mgr::VisualModeOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/watch.rs b/yazi-actor/src/mgr/watch.rs index a25591a6..48c28fef 100644 --- a/yazi-actor/src/mgr/watch.rs +++ b/yazi-actor/src/mgr/watch.rs @@ -3,7 +3,7 @@ use std::iter; use anyhow::Result; use yazi_macro::succ; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/yank.rs b/yazi-actor/src/mgr/yank.rs index 4926cbaf..6ba2569a 100644 --- a/yazi-actor/src/mgr/yank.rs +++ b/yazi-actor/src/mgr/yank.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_core::mgr::Yanked; use yazi_macro::{act, render}; use yazi_parser::mgr::YankOpt; -use yazi_shared::{event::Data, url::UrlBufCov}; +use yazi_shared::{data::Data, url::UrlBufCov}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/pick/arrow.rs b/yazi-actor/src/pick/arrow.rs index af3934a9..0dbbdd27 100644 --- a/yazi-actor/src/pick/arrow.rs +++ b/yazi-actor/src/pick/arrow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use yazi_widgets::Scrollable; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/pick/close.rs b/yazi-actor/src/pick/close.rs index 5028d66e..2962ab57 100644 --- a/yazi-actor/src/pick/close.rs +++ b/yazi-actor/src/pick/close.rs @@ -1,7 +1,7 @@ use anyhow::{Result, anyhow}; use yazi_macro::{render, succ}; use yazi_parser::pick::CloseOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/pick/show.rs b/yazi-actor/src/pick/show.rs index ab653e81..8eecc38c 100644 --- a/yazi-actor/src/pick/show.rs +++ b/yazi-actor/src/pick/show.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::pick::ShowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/spot/arrow.rs b/yazi-actor/src/spot/arrow.rs index 2384a96e..5e2d3b7c 100644 --- a/yazi-actor/src/spot/arrow.rs +++ b/yazi-actor/src/spot/arrow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/spot/close.rs b/yazi-actor/src/spot/close.rs index a14a18d4..d7656f43 100644 --- a/yazi-actor/src/spot/close.rs +++ b/yazi-actor/src/spot/close.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/spot/copy.rs b/yazi-actor/src/spot/copy.rs index 0cbf26a2..65ea3e4a 100644 --- a/yazi-actor/src/spot/copy.rs +++ b/yazi-actor/src/spot/copy.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::spot::CopyOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use yazi_widgets::CLIPBOARD; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/spot/swipe.rs b/yazi-actor/src/spot/swipe.rs index d2801424..f46c9d02 100644 --- a/yazi-actor/src/spot/swipe.rs +++ b/yazi-actor/src/spot/swipe.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::act; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/tasks/arrow.rs b/yazi-actor/src/tasks/arrow.rs index 2289123b..66eccbd9 100644 --- a/yazi-actor/src/tasks/arrow.rs +++ b/yazi-actor/src/tasks/arrow.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_core::tasks::Tasks; use yazi_macro::{render, succ}; use yazi_parser::ArrowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/tasks/cancel.rs b/yazi-actor/src/tasks/cancel.rs index 61acc0e0..bcb0219f 100644 --- a/yazi-actor/src/tasks/cancel.rs +++ b/yazi-actor/src/tasks/cancel.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/tasks/close.rs b/yazi-actor/src/tasks/close.rs index 386b28ca..bf0f87ef 100644 --- a/yazi-actor/src/tasks/close.rs +++ b/yazi-actor/src/tasks/close.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/tasks/inspect.rs b/yazi-actor/src/tasks/inspect.rs index 5d56a8d2..f3bd889d 100644 --- a/yazi-actor/src/tasks/inspect.rs +++ b/yazi-actor/src/tasks/inspect.rs @@ -7,7 +7,7 @@ use tokio::{io::{AsyncReadExt, stdin}, select, sync::mpsc, time}; use yazi_macro::succ; use yazi_parser::VoidOpt; use yazi_proxy::{AppProxy, HIDER}; -use yazi_shared::{event::Data, terminal_clear}; +use yazi_shared::{data::Data, terminal_clear}; use yazi_term::tty::TTY; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/tasks/open_with.rs b/yazi-actor/src/tasks/open_with.rs index ee73c406..b927d1a0 100644 --- a/yazi-actor/src/tasks/open_with.rs +++ b/yazi-actor/src/tasks/open_with.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::mgr::OpenWithOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; @@ -16,7 +16,7 @@ impl Actor for OpenWith { succ!(cx.tasks.process_from_opener( opt.cwd, opt.opener, - opt.targets.into_iter().map(|u| u.into_path2().into_os_string()).collect(), + opt.targets.into_iter().map(|u| u.into_os_str2()).collect(), )); } } diff --git a/yazi-actor/src/tasks/process_exec.rs b/yazi-actor/src/tasks/process_exec.rs index bdb3586b..c5ece66f 100644 --- a/yazi-actor/src/tasks/process_exec.rs +++ b/yazi-actor/src/tasks/process_exec.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::tasks::ProcessExecOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/tasks/show.rs b/yazi-actor/src/tasks/show.rs index a47b3175..1827b265 100644 --- a/yazi-actor/src/tasks/show.rs +++ b/yazi-actor/src/tasks/show.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/tasks/update_succeed.rs b/yazi-actor/src/tasks/update_succeed.rs index e10b7dcd..cf3b78c5 100644 --- a/yazi-actor/src/tasks/update_succeed.rs +++ b/yazi-actor/src/tasks/update_succeed.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::tasks::UpdateSucceedOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/which/callback.rs b/yazi-actor/src/which/callback.rs index 508f24af..7a672f65 100644 --- a/yazi-actor/src/which/callback.rs +++ b/yazi-actor/src/which/callback.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::which::CallbackOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/which/show.rs b/yazi-actor/src/which/show.rs index 0bbdede9..40b13c25 100644 --- a/yazi-actor/src/which/show.rs +++ b/yazi-actor/src/which/show.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::which::ShowOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Actor, Ctx}; diff --git a/yazi-boot/src/actions/debug.rs b/yazi-boot/src/actions/debug.rs index 1563812c..414486d7 100644 --- a/yazi-boot/src/actions/debug.rs +++ b/yazi-boot/src/actions/debug.rs @@ -1,9 +1,9 @@ -use std::{env, ffi::OsStr, fmt::Write, path::Path}; +use std::{env, ffi::OsStr, fmt::Write}; use regex::Regex; use yazi_adapter::Mux; use yazi_config::YAZI; -use yazi_shared::{timestamp_us, url::UrlBuf}; +use yazi_shared::{timestamp_us, url::Url}; use super::Actions; @@ -59,17 +59,17 @@ impl Actions { writeln!( s, " default : {:?}", - YAZI.opener.first(YAZI.open.all(UrlBuf::from(Path::new("f75a.txt")), "text/plain")) + YAZI.opener.first(YAZI.open.all(Url::regular("f75a.txt"), "text/plain")) )?; writeln!( s, " block-create: {:?}", - YAZI.opener.block(YAZI.open.all(UrlBuf::from(Path::new("bulk-create.txt")), "text/plain")) + YAZI.opener.block(YAZI.open.all(Url::regular("bulk-create.txt"), "text/plain")) )?; writeln!( s, " block-rename: {:?}", - YAZI.opener.block(YAZI.open.all(UrlBuf::from(Path::new("bulk-rename.txt")), "text/plain")) + YAZI.opener.block(YAZI.open.all(Url::regular("bulk-rename.txt"), "text/plain")) )?; writeln!(s, "\nMultiplexers")?; diff --git a/yazi-cli/src/package/hash.rs b/yazi-cli/src/package/hash.rs index 1730b464..88430f01 100644 --- a/yazi-cli/src/package/hash.rs +++ b/yazi-cli/src/package/hash.rs @@ -1,6 +1,7 @@ use anyhow::{Context, Result, bail}; use twox_hash::XxHash3_128; -use yazi_fs::{ok_or_not_found, provider::{DirReader, FileHolder, Provider, local::Local}}; +use yazi_fs::provider::{DirReader, FileHolder, Provider, local::Local}; +use yazi_macro::ok_or_not_found; use super::Dependency; @@ -14,7 +15,7 @@ impl Dependency { for file in files { h.write(file.as_bytes()); h.write(b"VpvFw9Atb7cWGOdqhZCra634CcJJRlsRl72RbZeV0vpG1\0"); - h.write(&ok_or_not_found(Local.read(dir.join(file)).await)?); + h.write(&ok_or_not_found!(Local.read(dir.join(file)).await)); } let mut assets = vec![]; diff --git a/yazi-cli/src/package/package.rs b/yazi-cli/src/package/package.rs index f07cfe26..617635da 100644 --- a/yazi-cli/src/package/package.rs +++ b/yazi-cli/src/package/package.rs @@ -3,7 +3,7 @@ use std::{path::PathBuf, str::FromStr}; use anyhow::{Context, Result, bail}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use yazi_fs::{Xdg, provider::{Provider, local::Local}}; -use yazi_macro::outln; +use yazi_macro::{ok_or_not_found, outln}; use super::Dependency; @@ -15,11 +15,8 @@ pub(crate) struct Package { impl Package { pub(crate) async fn load() -> Result { - Ok(match Local.read_to_string(Self::toml()).await { - Ok(s) => toml::from_str(&s)?, - Err(e) if e.kind() == std::io::ErrorKind::NotFound => Self::default(), - Err(e) => Err(e)?, - }) + let s = ok_or_not_found!(Local.read_to_string(Self::toml()).await); + Ok(toml::from_str(&s)?) } pub(crate) async fn add_many(&mut self, uses: &[String]) -> Result<()> { diff --git a/yazi-cli/src/shared/shared.rs b/yazi-cli/src/shared/shared.rs index 23a27561..f2077dd9 100644 --- a/yazi-cli/src/shared/shared.rs +++ b/yazi-cli/src/shared/shared.rs @@ -1,7 +1,8 @@ use std::{io, path::Path}; use tokio::io::AsyncWriteExt; -use yazi_fs::{ok_or_not_found, provider::{FileBuilder, Provider, local::{Gate, Local}}}; +use yazi_fs::provider::{FileBuilder, Provider, local::{Gate, Local}}; +use yazi_macro::ok_or_not_found; #[inline] pub async fn must_exists(path: impl AsRef) -> bool { @@ -18,7 +19,7 @@ pub async fn maybe_exists(path: impl AsRef) -> bool { pub async fn copy_and_seal(from: &Path, to: &Path) -> io::Result<()> { let b = Local.read(from).await?; - ok_or_not_found(remove_sealed(to).await)?; + ok_or_not_found!(remove_sealed(to).await); let mut file = Gate::default().create_new(true).write(true).truncate(true).open(to).await?; file.write_all(&b).await?; diff --git a/yazi-config/preset/yazi-default.toml b/yazi-config/preset/yazi-default.toml index fe16a463..42a431c0 100644 --- a/yazi-config/preset/yazi-default.toml +++ b/yazi-config/preset/yazi-default.toml @@ -34,6 +34,14 @@ edit = [ { run = 'code %*', orphan = true, desc = "code", for = "windows" }, { run = 'code -w %*', block = true, desc = "code (block)", for = "windows" }, ] +play = [ + { run = 'xdg-open "$1"', desc = "Play", for = "linux" }, + { run = 'open "$@"', desc = "Play", for = "macos" }, + { run = 'start "" "%1"', orphan = true, desc = "Play", for = "windows" }, + { run = 'termux-open "$1"', desc = "Play", for = "android" }, + { run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" }, + { run = 'mediainfo "%1" & pause', block = true, desc = "Show media info", for = "windows" }, +] open = [ { run = 'xdg-open "$1"', desc = "Open", for = "linux" }, { run = 'open "$@"', desc = "Open", for = "macos" }, @@ -51,13 +59,11 @@ extract = [ { run = 'ya pub extract --list "$@"', desc = "Extract here", for = "unix" }, { run = 'ya pub extract --list %*', desc = "Extract here", for = "windows" }, ] -play = [ - { run = 'xdg-open "$1"', desc = "Play", for = "linux" }, - { run = 'open "$@"', desc = "Play", for = "macos" }, - { run = 'start "" "%1"', orphan = true, desc = "Play", for = "windows" }, - { run = 'termux-open "$1"', desc = "Play", for = "android" }, - { run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" }, - { run = 'mediainfo "%1" & pause', block = true, desc = "Show media info", for = "windows" }, +download = [ + { run = 'ya emit download --open "$@"', desc = "Download and open", for = "unix" }, + { run = 'ya emit download --open %*', desc = "Download and open", for = "windows" }, + { run = 'ya emit download "$@"', desc = "Download", for = "unix" }, + { run = 'ya emit download %*', desc = "Download", for = "windows" }, ] [open] @@ -77,6 +83,8 @@ rules = [ { mime = "*/javascript", use = [ "edit", "reveal" ] }, # Empty file { mime = "inode/empty", use = [ "edit", "reveal" ] }, + # Virtual file system + { mime = "vfs/*", use = "download" }, # Fallback { url = "*", use = [ "open", "reveal" ] }, ] @@ -92,7 +100,8 @@ suppress_preload = false [plugin] fetchers = [ # Mimetype - { id = "mime", url = "*", run = "mime", prio = "high" }, + { id = "mime", url = "*/", run = "mime.dir", prio = "high" }, + { id = "mime", url = "*", run = "mime.file", prio = "high" }, ] spotters = [ { url = "*/", run = "folder" }, diff --git a/yazi-config/src/open/open.rs b/yazi-config/src/open/open.rs index 424a3c91..4fcd7d70 100644 --- a/yazi-config/src/open/open.rs +++ b/yazi-config/src/open/open.rs @@ -4,7 +4,7 @@ use anyhow::Result; use indexmap::IndexSet; use serde::Deserialize; use yazi_codegen::DeserializeOver2; -use yazi_shared::{MIME_DIR, url::UrlBuf}; +use yazi_shared::url::AsUrl; use crate::{Preset, open::OpenRule}; @@ -24,30 +24,31 @@ impl Deref for Open { } impl Open { - pub fn all<'a, 'b, P, M>(&'a self, url: P, mime: M) -> impl Iterator + 'b + pub fn all<'a, 'b, U, M>(&'a self, url: U, mime: M) -> impl Iterator + 'b where 'a: 'b, - P: AsRef + 'b, + U: AsUrl + 'b, M: AsRef + 'b, { - let is_dir = mime.as_ref() == MIME_DIR; + let is_dir = mime.as_ref().starts_with("folder/"); self .rules .iter() .filter(move |&r| { r.mime.as_ref().is_some_and(|p| p.match_mime(&mime)) - || r.url.as_ref().is_some_and(|p| p.match_url(&url, is_dir)) + || r.url.as_ref().is_some_and(|p| p.match_url(url.as_url(), is_dir)) }) .flat_map(|r| &r.r#use) .map(String::as_str) } - pub fn common<'a>( - &'a self, - targets: &[(impl AsRef, impl AsRef)], - ) -> IndexSet<&'a str> { + pub fn common<'a, 'b, U, M>(&'a self, targets: &'b [(U, M)]) -> IndexSet<&'a str> + where + &'b U: AsUrl, + M: AsRef, + { let each: Vec> = targets - .iter() + .into_iter() .map(|(u, m)| self.all(u, m).collect::>()) .filter(|s| !s.is_empty()) .collect(); diff --git a/yazi-config/src/pattern.rs b/yazi-config/src/pattern.rs index e922ed98..66e0cfb6 100644 --- a/yazi-config/src/pattern.rs +++ b/yazi-config/src/pattern.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use anyhow::Result; use globset::GlobBuilder; use serde::Deserialize; -use yazi_shared::{scheme::{SchemeCow, SchemeRef}, url::UrlBuf}; +use yazi_shared::{scheme::{SchemeCow, SchemeRef}, url::Url}; #[derive(Debug, Deserialize)] #[serde(try_from = "String")] @@ -17,14 +17,14 @@ pub struct Pattern { } impl Pattern { - pub fn match_url(&self, url: impl AsRef, is_dir: bool) -> bool { - let url = url.as_ref(); + pub fn match_url<'a>(&self, url: impl Into>, is_dir: bool) -> bool { + let url = url.into(); if is_dir != self.is_dir { return false; } else if self.is_star { return true; - } else if !self.scheme.matches(&url.scheme) { + } else if !self.scheme.matches(url.scheme) { return false; } @@ -121,10 +121,12 @@ impl PatternScheme { // --- Tests #[cfg(test)] mod tests { + use yazi_shared::url::UrlCow; + use super::*; fn matches(glob: &str, url: &str) -> bool { - Pattern::from_str(glob).unwrap().match_url(UrlBuf::from_str(url).unwrap(), false) + Pattern::from_str(glob).unwrap().match_url(&UrlCow::try_from(url).unwrap(), false) } #[cfg(unix)] diff --git a/yazi-config/src/plugin/fetcher.rs b/yazi-config/src/plugin/fetcher.rs index a4d0f14a..6638c319 100644 --- a/yazi-config/src/plugin/fetcher.rs +++ b/yazi-config/src/plugin/fetcher.rs @@ -1,5 +1,6 @@ use serde::Deserialize; -use yazi_shared::{MIME_DIR, event::Cmd, url::UrlBuf}; +use yazi_fs::File; +use yazi_shared::event::Cmd; use crate::{Pattern, Priority}; @@ -18,8 +19,8 @@ pub struct Fetcher { impl Fetcher { #[inline] - pub fn matches(&self, url: &UrlBuf, mime: &str) -> bool { + pub fn matches(&self, file: &File, mime: &str) -> bool { self.mime.as_ref().is_some_and(|p| p.match_mime(mime)) - || self.url.as_ref().is_some_and(|p| p.match_url(url, mime == MIME_DIR)) + || self.url.as_ref().is_some_and(|p| p.match_url(&file.url, file.is_dir())) } } diff --git a/yazi-config/src/plugin/plugin.rs b/yazi-config/src/plugin/plugin.rs index d4c54ed1..db83c78a 100644 --- a/yazi-config/src/plugin/plugin.rs +++ b/yazi-config/src/plugin/plugin.rs @@ -4,7 +4,6 @@ use serde::Deserialize; use tracing::warn; use yazi_codegen::DeserializeOver2; use yazi_fs::File; -use yazi_shared::url::UrlBuf; use super::{Fetcher, Preloader, Previewer, Spotter}; use crate::{Preset, plugin::MAX_PREWORKERS}; @@ -39,12 +38,12 @@ pub struct Plugin { impl Plugin { pub fn fetchers<'a, 'b: 'a>( &'b self, - url: &'a UrlBuf, + file: &'a File, mime: &'a str, ) -> impl Iterator + 'a { let mut seen = HashSet::new(); self.fetchers.iter().filter(move |&f| { - if seen.contains(&f.id) || !f.matches(url, mime) { + if seen.contains(&f.id) || !f.matches(file, mime) { return false; } seen.insert(&f.id); @@ -55,7 +54,7 @@ impl Plugin { pub fn mime_fetchers(&self, files: Vec) -> impl Iterator)> { let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default(); for f in files { - let found = self.fetchers.iter().find(|&g| g.id == "mime" && g.matches(&f.url, "")); + let found = self.fetchers.iter().find(|&g| g.id == "mime" && g.matches(&f, "")); if let Some(g) = found { tasks[g.idx as usize].push(f); } else { @@ -68,18 +67,18 @@ impl Plugin { }) } - pub fn spotter(&self, url: &UrlBuf, mime: &str) -> Option<&Spotter> { - self.spotters.iter().find(|&p| p.matches(url, mime)) + pub fn spotter(&self, file: &File, mime: &str) -> Option<&Spotter> { + self.spotters.iter().find(|&p| p.matches(file, mime)) } pub fn preloaders<'a, 'b: 'a>( &'b self, - url: &'a UrlBuf, + file: &'a File, mime: &'a str, ) -> impl Iterator + 'a { let mut next = true; self.preloaders.iter().filter(move |&p| { - if !next || !p.matches(url, mime) { + if !next || !p.matches(file, mime) { return false; } next = p.next; @@ -87,8 +86,8 @@ impl Plugin { }) } - pub fn previewer(&self, url: &UrlBuf, mime: &str) -> Option<&Previewer> { - self.previewers.iter().find(|&p| p.matches(url, mime)) + pub fn previewer(&self, file: &File, mime: &str) -> Option<&Previewer> { + self.previewers.iter().find(|&p| p.matches(file, mime)) } } diff --git a/yazi-config/src/plugin/preloader.rs b/yazi-config/src/plugin/preloader.rs index b7ed9e3e..3af758ca 100644 --- a/yazi-config/src/plugin/preloader.rs +++ b/yazi-config/src/plugin/preloader.rs @@ -1,5 +1,6 @@ use serde::Deserialize; -use yazi_shared::{MIME_DIR, event::Cmd, url::UrlBuf}; +use yazi_fs::File; +use yazi_shared::event::Cmd; use crate::{Pattern, Priority}; @@ -19,8 +20,8 @@ pub struct Preloader { impl Preloader { #[inline] - pub fn matches(&self, url: &UrlBuf, mime: &str) -> bool { + pub fn matches(&self, file: &File, mime: &str) -> bool { self.mime.as_ref().is_some_and(|p| p.match_mime(mime)) - || self.url.as_ref().is_some_and(|p| p.match_url(url, mime == MIME_DIR)) + || self.url.as_ref().is_some_and(|p| p.match_url(&file.url, file.is_dir())) } } diff --git a/yazi-config/src/plugin/previewer.rs b/yazi-config/src/plugin/previewer.rs index 2aff9340..e98cb24c 100644 --- a/yazi-config/src/plugin/previewer.rs +++ b/yazi-config/src/plugin/previewer.rs @@ -1,5 +1,6 @@ use serde::Deserialize; -use yazi_shared::{MIME_DIR, event::Cmd, url::UrlBuf}; +use yazi_fs::File; +use yazi_shared::event::Cmd; use crate::Pattern; @@ -12,9 +13,9 @@ pub struct Previewer { impl Previewer { #[inline] - pub fn matches(&self, url: &UrlBuf, mime: &str) -> bool { + pub fn matches(&self, file: &File, mime: &str) -> bool { self.mime.as_ref().is_some_and(|p| p.match_mime(mime)) - || self.url.as_ref().is_some_and(|p| p.match_url(url, mime == MIME_DIR)) + || self.url.as_ref().is_some_and(|p| p.match_url(&file.url, file.is_dir())) } #[inline] diff --git a/yazi-config/src/plugin/spotter.rs b/yazi-config/src/plugin/spotter.rs index f8a1d3eb..9994370a 100644 --- a/yazi-config/src/plugin/spotter.rs +++ b/yazi-config/src/plugin/spotter.rs @@ -1,5 +1,6 @@ use serde::Deserialize; -use yazi_shared::{MIME_DIR, event::Cmd, url::UrlBuf}; +use yazi_fs::File; +use yazi_shared::event::Cmd; use crate::Pattern; @@ -12,9 +13,9 @@ pub struct Spotter { impl Spotter { #[inline] - pub fn matches(&self, url: &UrlBuf, mime: &str) -> bool { + pub fn matches(&self, file: &File, mime: &str) -> bool { self.mime.as_ref().is_some_and(|p| p.match_mime(mime)) - || self.url.as_ref().is_some_and(|p| p.match_url(url, mime == MIME_DIR)) + || self.url.as_ref().is_some_and(|p| p.match_url(&file.url, file.is_dir())) } #[inline] diff --git a/yazi-config/src/vfs/provider.rs b/yazi-config/src/vfs/provider.rs index e21a7700..24f5b5f0 100644 --- a/yazi-config/src/vfs/provider.rs +++ b/yazi-config/src/vfs/provider.rs @@ -1,6 +1,8 @@ use std::{io, path::PathBuf}; use serde::{Deserialize, Serialize}; +use yazi_fs::path::expand_url; +use yazi_shared::url::Url; #[derive(Deserialize, Serialize)] #[serde(tag = "type", rename_all = "kebab-case")] @@ -19,9 +21,9 @@ impl TryFrom<&'static Provider> for &'static ProviderSftp { } impl Provider { - pub(super) fn reshape(self) -> io::Result { + pub(super) fn reshape(&mut self) -> io::Result<()> { match self { - Self::Sftp(p) => p.reshape().map(Self::Sftp), + Self::Sftp(p) => p.reshape(), } } } @@ -33,18 +35,32 @@ pub struct ProviderSftp { pub user: String, pub port: u16, pub password: Option, - pub key_file: Option, + #[serde(default)] + pub key_file: PathBuf, pub key_passphrase: Option, - // FIXME: set default: $SSH_AUTH_SOCK - pub identity_agent: Option, + #[serde(default)] + pub identity_agent: PathBuf, } impl ProviderSftp { - fn reshape(self) -> io::Result { - // FIXME: expand the path - // if let Some(key_file) = self.key_file {} - // if let Some(identity_agent) = self.identity_agent {} + fn reshape(&mut self) -> io::Result<()> { + if !self.key_file.as_os_str().is_empty() { + self.key_file = expand_url(Url::regular(&self.key_file)) + .into_path() + .ok_or_else(|| io::Error::other("key_file must be a path within local filesystem"))?; + } - Ok(self) + self.identity_agent = if self.identity_agent.as_os_str().is_empty() { + std::env::var_os("SSH_AUTH_SOCK") + .map(PathBuf::from) + .filter(|p| p.is_absolute()) + .unwrap_or_default() + } else { + expand_url(Url::regular(&self.identity_agent)) + .into_path() + .ok_or_else(|| io::Error::other("identity_agent must be a path within local filesystem"))? + }; + + Ok(()) } } diff --git a/yazi-config/src/vfs/vfs.rs b/yazi-config/src/vfs/vfs.rs index 715a34a0..3459ad82 100644 --- a/yazi-config/src/vfs/vfs.rs +++ b/yazi-config/src/vfs/vfs.rs @@ -47,13 +47,15 @@ impl Vfs { }))) } - fn reshape(self) -> io::Result { - for name in self.providers.keys() { + fn reshape(mut self) -> io::Result { + for (name, provider) in &mut self.providers { if name.is_empty() || name.len() > 20 { Err(io::Error::other(format!("VFS name `{name}` must be between 1 and 20 characters")))?; } else if !name.bytes().all(|b| matches!(b, b'0'..=b'9' | b'a'..=b'z' | b'-')) { Err(io::Error::other(format!("VFS name `{name}` must be in kebab-case")))?; } + + provider.reshape()?; } Ok(self) diff --git a/yazi-core/src/mgr/mimetype.rs b/yazi-core/src/mgr/mimetype.rs index 029232cf..56f104f5 100644 --- a/yazi-core/src/mgr/mimetype.rs +++ b/yazi-core/src/mgr/mimetype.rs @@ -1,27 +1,18 @@ use hashbrown::HashMap; -use yazi_fs::File; -use yazi_shared::{MIME_DIR, pool::{InternStr, Symbol}, url::{Url, UrlBufCov, UrlCov}}; +use yazi_shared::{pool::Symbol, url::{Url, UrlBufCov, UrlCov}}; #[derive(Default)] pub struct Mimetype(HashMap>); impl Mimetype { - pub fn by_url<'a>(&self, url: impl Into>) -> Option<&str> { + pub fn get<'a, 'b>(&'a self, url: impl Into>) -> Option<&'a str> { self.0.get(&UrlCov::new(url)).map(|s| s.as_ref()) } - pub fn by_url_owned<'a>(&self, url: impl Into>) -> Option> { + pub fn owned<'a>(&self, url: impl Into>) -> Option> { self.0.get(&UrlCov::new(url)).cloned() } - pub fn by_file(&self, file: &File) -> Option<&str> { - if file.is_dir() { Some(MIME_DIR) } else { self.by_url(&file.url) } - } - - pub fn by_file_owned(&self, file: &File) -> Option> { - if file.is_dir() { Some(MIME_DIR.intern()) } else { self.by_url_owned(&file.url) } - } - pub fn contains<'a>(&self, url: impl Into>) -> bool { self.0.contains_key(&UrlCov::new(url)) } diff --git a/yazi-core/src/spot/spot.rs b/yazi-core/src/spot/spot.rs index 2e661146..34034168 100644 --- a/yazi-core/src/spot/spot.rs +++ b/yazi-core/src/spot/spot.rs @@ -22,7 +22,7 @@ impl Spot { return; } - let Some(spotter) = YAZI.plugin.spotter(&file.url, &mime) else { + let Some(spotter) = YAZI.plugin.spotter(&file, &mime) else { return self.reset(); }; diff --git a/yazi-core/src/tab/preview.rs b/yazi-core/src/tab/preview.rs index d1ad23ca..7d48d9f5 100644 --- a/yazi-core/src/tab/preview.rs +++ b/yazi-core/src/tab/preview.rs @@ -9,7 +9,7 @@ use yazi_fs::{File, Files, FilesOp, cha::Cha}; use yazi_macro::render; use yazi_parser::mgr::PreviewLock; use yazi_plugin::{external::Highlighter, isolate}; -use yazi_shared::{MIME_DIR, pool::{InternStr, Symbol}, url::UrlBuf}; +use yazi_shared::{pool::{InternStr, Symbol}, url::UrlBuf}; use yazi_vfs::{VfsFiles, VfsFilesOp}; #[derive(Default)] @@ -29,7 +29,7 @@ impl Preview { return; } - let Some(previewer) = YAZI.plugin.previewer(&file.url, &mime) else { + let Some(previewer) = YAZI.plugin.previewer(&file, &mime) else { return self.reset(); }; @@ -38,16 +38,18 @@ impl Preview { } pub fn go_folder(&mut self, file: File, dir: Option, force: bool) { - let same = self.same_file(&file, MIME_DIR); + const MIME: &str = "folder/lock"; + + let same = self.same_file(&file, MIME); let (wd, cha, internal) = (file.url_owned(), file.cha, file.url.is_internal()); - self.go(file, MIME_DIR.intern(), force); + self.go(file, MIME.intern(), force); if same || !internal { return; } self.lock = - Some(PreviewLock { url: wd.clone(), cha, mime: MIME_DIR.to_owned(), ..Default::default() }); + Some(PreviewLock { url: wd.clone(), cha, mime: MIME.to_owned(), ..Default::default() }); self.folder_loader.take().map(|h| h.abort()); self.folder_loader = Some(tokio::spawn(async move { let Some(new) = Files::assert_stale(&wd, dir.unwrap_or_default()).await else { return }; diff --git a/yazi-core/src/tasks/preload.rs b/yazi-core/src/tasks/preload.rs index 42e7b716..3139f14e 100644 --- a/yazi-core/src/tasks/preload.rs +++ b/yazi-core/src/tasks/preload.rs @@ -10,7 +10,7 @@ impl Tasks { let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default(); for f in paged { let hash = f.hash_u64(); - for g in YAZI.plugin.fetchers(&f.url, mimetype.by_file(f).unwrap_or_default()) { + for g in YAZI.plugin.fetchers(f, mimetype.get(&f.url).unwrap_or_default()) { match loaded.get_mut(&hash) { Some(n) if *n & (1 << g.idx) != 0 => continue, Some(n) => *n |= 1 << g.idx, @@ -32,7 +32,7 @@ impl Tasks { let mut loaded = self.scheduler.prework.loaded.lock(); for f in paged { let hash = f.hash_u64(); - for p in YAZI.plugin.preloaders(&f.url, mimetype.by_file(f).unwrap_or_default()) { + for p in YAZI.plugin.preloaders(f, mimetype.get(&f.url).unwrap_or_default()) { match loaded.get_mut(&hash) { Some(n) if *n & (1 << p.idx) != 0 => continue, Some(n) => *n |= 1 << p.idx, diff --git a/yazi-core/src/tasks/process.rs b/yazi-core/src/tasks/process.rs index efaca89d..72db4644 100644 --- a/yazi-core/src/tasks/process.rs +++ b/yazi-core/src/tasks/process.rs @@ -1,14 +1,19 @@ -use std::{borrow::Cow, ffi::OsString, mem}; +use std::{borrow::Cow, ffi::OsStr, mem}; use hashbrown::HashMap; use yazi_config::{YAZI, opener::OpenerRule}; use yazi_parser::tasks::ProcessExecOpt; -use yazi_shared::url::UrlBuf; +use yazi_shared::url::{UrlBuf, UrlCow}; use super::Tasks; impl Tasks { - pub fn process_from_files(&self, cwd: UrlBuf, hovered: UrlBuf, targets: Vec<(UrlBuf, &str)>) { + pub fn process_from_files( + &self, + cwd: UrlBuf, + hovered: UrlCow<'static>, + targets: Vec<(UrlCow<'static>, &str)>, + ) { let mut openers = HashMap::new(); for (url, mime) in targets { if let Some(opener) = YAZI.opener.first(YAZI.open.all(&url, mime)) { @@ -19,7 +24,7 @@ impl Tasks { self.process_from_opener( cwd.clone(), Cow::Borrowed(opener), - args.into_iter().map(|u| u.into_path2().into_os_string()).collect(), + args.into_iter().map(|u| u.into_os_str2()).collect(), ); } } @@ -28,7 +33,7 @@ impl Tasks { &self, cwd: UrlBuf, opener: Cow<'static, OpenerRule>, - mut args: Vec, + mut args: Vec>, ) { if opener.spread { self.scheduler.process_open(ProcessExecOpt { cwd, opener, args, done: None }); diff --git a/yazi-dds/src/ember/custom.rs b/yazi-dds/src/ember/custom.rs index e7fb40e1..4b05f30a 100644 --- a/yazi-dds/src/ember/custom.rs +++ b/yazi-dds/src/ember/custom.rs @@ -1,6 +1,6 @@ use mlua::{IntoLua, Lua, Value}; use serde::Serialize; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use super::Ember; use crate::Sendable; diff --git a/yazi-dds/src/sendable.rs b/yazi-dds/src/sendable.rs index faa3bb06..a1703985 100644 --- a/yazi-dds/src/sendable.rs +++ b/yazi-dds/src/sendable.rs @@ -3,7 +3,7 @@ use std::{any::TypeId, borrow::Cow}; use hashbrown::HashMap; use mlua::{ExternalError, IntoLua, Lua, MultiValue, Table, Value}; use ordered_float::OrderedFloat; -use yazi_shared::{event::{Data, DataKey}, replace_cow}; +use yazi_shared::{data::{Data, DataKey}, replace_cow}; pub struct Sendable; diff --git a/yazi-dds/src/spark/spark.rs b/yazi-dds/src/spark/spark.rs index e5c6eb36..8d881a8f 100644 --- a/yazi-dds/src/spark/spark.rs +++ b/yazi-dds/src/spark/spark.rs @@ -15,6 +15,7 @@ pub enum Spark<'a> { Close(yazi_parser::mgr::CloseOpt), Copy(yazi_parser::mgr::CopyOpt), Create(yazi_parser::mgr::CreateOpt), + Download(yazi_parser::mgr::DownloadOpt), Enter(yazi_parser::VoidOpt), Escape(yazi_parser::mgr::EscapeOpt), EscapeFilter(yazi_parser::VoidOpt), @@ -137,6 +138,7 @@ impl<'a> IntoLua for Spark<'a> { Self::Close(b) => b.into_lua(lua), Self::Copy(b) => b.into_lua(lua), Self::Create(b) => b.into_lua(lua), + Self::Download(b) => b.into_lua(lua), Self::Enter(b) => b.into_lua(lua), Self::Escape(b) => b.into_lua(lua), Self::EscapeFilter(b) => b.into_lua(lua), @@ -280,6 +282,7 @@ try_from_spark!(mgr::CdOpt, mgr:cd); try_from_spark!(mgr::CloseOpt, mgr:close); try_from_spark!(mgr::CopyOpt, mgr:copy); try_from_spark!(mgr::CreateOpt, mgr:create); +try_from_spark!(mgr::DownloadOpt, mgr:download); try_from_spark!(mgr::EscapeOpt, mgr:escape); try_from_spark!(mgr::FilterOpt, mgr:filter, mgr:filter_do); try_from_spark!(mgr::FindArrowOpt, mgr:find_arrow); diff --git a/yazi-fm/src/app/commands/accept_payload.rs b/yazi-fm/src/app/commands/accept_payload.rs index a95b70eb..2648869f 100644 --- a/yazi-fm/src/app/commands/accept_payload.rs +++ b/yazi-fm/src/app/commands/accept_payload.rs @@ -6,7 +6,7 @@ use yazi_binding::runtime_mut; use yazi_dds::{LOCAL, Payload, REMOTE}; use yazi_macro::succ; use yazi_plugin::LUA; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::{data::Data, event::CmdCow}; use crate::app::App; diff --git a/yazi-fm/src/app/commands/bootstrap.rs b/yazi-fm/src/app/commands/bootstrap.rs index eb08a1ff..b4733cfd 100644 --- a/yazi-fm/src/app/commands/bootstrap.rs +++ b/yazi-fm/src/app/commands/bootstrap.rs @@ -3,7 +3,7 @@ use yazi_actor::Ctx; use yazi_boot::BOOT; use yazi_macro::act; use yazi_parser::{VoidOpt, mgr::CdSource}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; diff --git a/yazi-fm/src/app/commands/deprecate.rs b/yazi-fm/src/app/commands/deprecate.rs index 96a36d7c..5537a547 100644 --- a/yazi-fm/src/app/commands/deprecate.rs +++ b/yazi-fm/src/app/commands/deprecate.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::app::{DeprecateOpt, NotifyLevel, NotifyOpt}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; @@ -9,7 +9,7 @@ impl App { pub(crate) fn deprecate(&mut self, opt: DeprecateOpt) -> Result { succ!(self.core.notify.push(NotifyOpt { title: "Deprecated API".to_owned(), - content: opt.content, + content: opt.content.into_owned(), level: NotifyLevel::Warn, timeout: std::time::Duration::from_secs(20), })); diff --git a/yazi-fm/src/app/commands/mouse.rs b/yazi-fm/src/app/commands/mouse.rs index 70cefe6e..2cba3fe2 100644 --- a/yazi-fm/src/app/commands/mouse.rs +++ b/yazi-fm/src/app/commands/mouse.rs @@ -7,7 +7,7 @@ use yazi_config::YAZI; use yazi_macro::succ; use yazi_parser::app::MouseOpt; use yazi_plugin::LUA; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; diff --git a/yazi-fm/src/app/commands/notify.rs b/yazi-fm/src/app/commands/notify.rs index 127a1876..49ad97dc 100644 --- a/yazi-fm/src/app/commands/notify.rs +++ b/yazi-fm/src/app/commands/notify.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::app::NotifyOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; diff --git a/yazi-fm/src/app/commands/plugin.rs b/yazi-fm/src/app/commands/plugin.rs index 5a71d4a2..e8986f19 100644 --- a/yazi-fm/src/app/commands/plugin.rs +++ b/yazi-fm/src/app/commands/plugin.rs @@ -9,7 +9,7 @@ use yazi_macro::succ; use yazi_parser::app::{PluginMode, PluginOpt}; use yazi_plugin::{LUA, loader::{LOADER, Loader}}; use yazi_proxy::AppProxy; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; diff --git a/yazi-fm/src/app/commands/reflow.rs b/yazi-fm/src/app/commands/reflow.rs index f6f19314..c0cfa38f 100644 --- a/yazi-fm/src/app/commands/reflow.rs +++ b/yazi-fm/src/app/commands/reflow.rs @@ -6,7 +6,7 @@ use yazi_actor::lives::Lives; use yazi_config::LAYOUT; use yazi_macro::{render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Root, app::App}; diff --git a/yazi-fm/src/app/commands/render.rs b/yazi-fm/src/app/commands/render.rs index 8d71a41c..123ccfe6 100644 --- a/yazi-fm/src/app/commands/render.rs +++ b/yazi-fm/src/app/commands/render.rs @@ -7,7 +7,7 @@ use yazi_actor::{Ctx, lives::Lives}; use yazi_binding::elements::COLLISION; use yazi_macro::{act, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::{Data, NEED_RENDER}; +use yazi_shared::{data::Data, event::NEED_RENDER}; use yazi_term::tty::TTY; use crate::{app::App, root::Root}; diff --git a/yazi-fm/src/app/commands/resize.rs b/yazi-fm/src/app/commands/resize.rs index 97f11e3b..24ab0a42 100644 --- a/yazi-fm/src/app/commands/resize.rs +++ b/yazi-fm/src/app/commands/resize.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_actor::Ctx; use yazi_macro::act; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; diff --git a/yazi-fm/src/app/commands/resume.rs b/yazi-fm/src/app/commands/resume.rs index b0a17ef4..1df67288 100644 --- a/yazi-fm/src/app/commands/resume.rs +++ b/yazi-fm/src/app/commands/resume.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{Term, app::App}; diff --git a/yazi-fm/src/app/commands/stop.rs b/yazi-fm/src/app/commands/stop.rs index 45c796c0..4868639b 100644 --- a/yazi-fm/src/app/commands/stop.rs +++ b/yazi-fm/src/app/commands/stop.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::succ; use yazi_parser::app::StopOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; diff --git a/yazi-fm/src/app/commands/update_notify.rs b/yazi-fm/src/app/commands/update_notify.rs index 369f0d1c..cb1a5e79 100644 --- a/yazi-fm/src/app/commands/update_notify.rs +++ b/yazi-fm/src/app/commands/update_notify.rs @@ -3,7 +3,7 @@ use ratatui::layout::Rect; use yazi_adapter::Dimension; use yazi_macro::act; use yazi_parser::notify::TickOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{app::App, notify}; diff --git a/yazi-fm/src/app/commands/update_progress.rs b/yazi-fm/src/app/commands/update_progress.rs index b406fde8..6931a12d 100644 --- a/yazi-fm/src/app/commands/update_progress.rs +++ b/yazi-fm/src/app/commands/update_progress.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_actor::Ctx; use yazi_macro::{act, render, succ}; use yazi_parser::app::UpdateProgressOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::app::App; diff --git a/yazi-fm/src/dispatcher.rs b/yazi-fm/src/dispatcher.rs index 83025aba..ebc2bd73 100644 --- a/yazi-fm/src/dispatcher.rs +++ b/yazi-fm/src/dispatcher.rs @@ -4,7 +4,7 @@ use anyhow::Result; use crossterm::event::KeyEvent; use yazi_config::keymap::Key; use yazi_macro::{act, emit, succ}; -use yazi_shared::event::{CmdCow, Data, Event, NEED_RENDER}; +use yazi_shared::{data::Data, event::{CmdCow, Event, NEED_RENDER}}; use yazi_widgets::input::InputMode; use crate::{Executor, Router, app::App}; diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 5dfea864..84b3151e 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_actor::Ctx; use yazi_macro::{act, succ}; -use yazi_shared::{Layer, event::{CmdCow, Data}}; +use yazi_shared::{Layer, data::Data, event::CmdCow}; use yazi_widgets::input::InputMode; use crate::app::App; @@ -134,6 +134,9 @@ impl<'a> Executor<'a> { on!(tab_switch); on!(tab_swap); + // VFS + on!(download); + match cmd.name.as_ref() { // Help "help" => act!(help:toggle, cx, Layer::Mgr), diff --git a/yazi-fs/src/url.rs b/yazi-fs/src/url.rs index 3b4137ad..6b2e00e3 100644 --- a/yazi-fs/src/url.rs +++ b/yazi-fs/src/url.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use twox_hash::XxHash3_128; -use yazi_shared::{scheme::SchemeRef, url::{Url, UrlBuf}}; +use yazi_shared::{scheme::SchemeRef, url::{Url, UrlBuf, UrlCow}}; use crate::Xdg; @@ -30,3 +30,7 @@ impl FsUrl for Url<'_> { impl FsUrl for UrlBuf { fn cache(&self) -> Option { self.as_url().cache() } } + +impl FsUrl for UrlCow<'_> { + fn cache(&self) -> Option { self.as_url().cache() } +} diff --git a/yazi-macro/src/event.rs b/yazi-macro/src/event.rs index a42092b4..2dc0447e 100644 --- a/yazi-macro/src/event.rs +++ b/yazi-macro/src/event.rs @@ -30,9 +30,9 @@ macro_rules! relay { #[macro_export] macro_rules! succ { ($data:expr) => { - return Ok(yazi_shared::event::Data::from($data)) + return Ok(yazi_shared::data::Data::from($data)) }; () => { - return Ok(yazi_shared::event::Data::Nil) + return Ok(yazi_shared::data::Data::Nil) }; } diff --git a/yazi-parser/src/app/deprecate.rs b/yazi-parser/src/app/deprecate.rs index 6bd47bb6..10c72ed9 100644 --- a/yazi-parser/src/app/deprecate.rs +++ b/yazi-parser/src/app/deprecate.rs @@ -1,18 +1,18 @@ use anyhow::bail; -use yazi_shared::event::CmdCow; +use yazi_shared::{SStr, event::CmdCow}; pub struct DeprecateOpt { - pub content: String, + pub content: SStr, } impl TryFrom for DeprecateOpt { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { - let Some(content) = c.take_str("content") else { + let Ok(content) = c.take("content") else { bail!("Invalid 'content' in DeprecateOpt"); }; - Ok(Self { content: content.into_owned() }) + Ok(Self { content }) } } diff --git a/yazi-parser/src/app/plugin.rs b/yazi-parser/src/app/plugin.rs index 75068fd2..4b7114bf 100644 --- a/yazi-parser/src/app/plugin.rs +++ b/yazi-parser/src/app/plugin.rs @@ -1,9 +1,10 @@ -use std::{borrow::Cow, fmt::Debug}; +use std::{borrow::Cow, fmt::Debug, str::FromStr}; use anyhow::bail; use hashbrown::HashMap; use mlua::{Lua, Table}; -use yazi_shared::{SStr, event::{Cmd, CmdCow, Data, DataKey}}; +use serde::Deserialize; +use yazi_shared::{SStr, data::{Data, DataKey}, event::{Cmd, CmdCow}}; pub type PluginCallback = Box mlua::Result<()> + Send + Sync>; @@ -23,18 +24,18 @@ impl TryFrom for PluginOpt { return Ok(opt); } - let Some(id) = c.take_first_str().filter(|s| !s.is_empty()) else { + let Some(id) = c.take_first::().ok().filter(|s| !s.is_empty()) else { bail!("plugin id cannot be empty"); }; - let args = if let Some(s) = c.second_str() { + let args = if let Ok(s) = c.second() { let (words, last) = yazi_shared::shell::split_unix(s, true)?; Cmd::parse_args(words.into_iter(), last, true)? } else { Default::default() }; - let mode = c.str("mode").map(Into::into).unwrap_or_default(); + let mode = c.str("mode").parse().unwrap_or_default(); Ok(Self { id: Self::normalize_id(id), args, mode, cb: c.take_any("callback") }) } } @@ -72,7 +73,8 @@ impl PluginOpt { } // --- Mode -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "kebab-case")] pub enum PluginMode { #[default] Auto, @@ -80,13 +82,11 @@ pub enum PluginMode { Async, } -impl From<&str> for PluginMode { - fn from(s: &str) -> Self { - match s { - "sync" => Self::Sync, - "async" => Self::Async, - _ => Self::Auto, - } +impl FromStr for PluginMode { + type Err = serde::de::value::Error; + + fn from_str(s: &str) -> Result { + Self::deserialize(serde::de::value::StrDeserializer::new(s)) } } diff --git a/yazi-parser/src/arrow.rs b/yazi-parser/src/arrow.rs index a8a164c4..9aa9627d 100644 --- a/yazi-parser/src/arrow.rs +++ b/yazi-parser/src/arrow.rs @@ -13,11 +13,11 @@ impl TryFrom for ArrowOpt { type Error = anyhow::Error; fn try_from(c: CmdCow) -> Result { - let Some(step) = c.first() else { + let Ok(step) = c.first() else { bail!("'step' is required for ArrowOpt"); }; - Ok(Self { step: step.try_into()? }) + Ok(Self { step }) } } diff --git a/yazi-parser/src/cmp/trigger.rs b/yazi-parser/src/cmp/trigger.rs index c5b310e2..2e60f2d0 100644 --- a/yazi-parser/src/cmp/trigger.rs +++ b/yazi-parser/src/cmp/trigger.rs @@ -9,7 +9,7 @@ pub struct TriggerOpt { impl From for TriggerOpt { fn from(mut c: CmdCow) -> Self { - Self { word: c.take_first_str().unwrap_or_default(), ticket: c.id("ticket") } + Self { word: c.take_first().unwrap_or_default(), ticket: c.get("ticket").ok() } } } diff --git a/yazi-parser/src/help/toggle.rs b/yazi-parser/src/help/toggle.rs index c841ab54..f333bbd5 100644 --- a/yazi-parser/src/help/toggle.rs +++ b/yazi-parser/src/help/toggle.rs @@ -1,4 +1,3 @@ -use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; use yazi_shared::{Layer, event::CmdCow}; @@ -10,13 +9,7 @@ pub struct ToggleOpt { impl TryFrom for ToggleOpt { type Error = anyhow::Error; - fn try_from(c: CmdCow) -> Result { - let Some(layer) = c.first_str() else { - bail!("Invalid 'layer' in Toggle"); - }; - - Ok(Self { layer: layer.parse()? }) - } + fn try_from(c: CmdCow) -> Result { Ok(Self { layer: c.str(0).parse()? }) } } impl From for ToggleOpt { diff --git a/yazi-parser/src/input/complete.rs b/yazi-parser/src/input/complete.rs index b4db4c56..557aad21 100644 --- a/yazi-parser/src/input/complete.rs +++ b/yazi-parser/src/input/complete.rs @@ -18,7 +18,7 @@ impl TryFrom for CompleteOpt { bail!("Invalid 'item' in CompleteOpt"); }; - Ok(Self { item, _ticket: c.id("ticket").unwrap_or_default() }) + Ok(Self { item, _ticket: c.get("ticket").unwrap_or_default() }) } } diff --git a/yazi-parser/src/input/kill.rs b/yazi-parser/src/input/kill.rs index 267e5f6b..51cbd962 100644 --- a/yazi-parser/src/input/kill.rs +++ b/yazi-parser/src/input/kill.rs @@ -7,7 +7,7 @@ pub struct KillOpt { } impl From for KillOpt { - fn from(mut c: CmdCow) -> Self { Self { kind: c.take_first_str().unwrap_or_default() } } + fn from(mut c: CmdCow) -> Self { Self { kind: c.take_first().unwrap_or_default() } } } impl FromLua for KillOpt { diff --git a/yazi-parser/src/input/move.rs b/yazi-parser/src/input/move.rs index c2b14ab9..8870e7bc 100644 --- a/yazi-parser/src/input/move.rs +++ b/yazi-parser/src/input/move.rs @@ -2,7 +2,7 @@ use std::{num::ParseIntError, str::FromStr}; use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::{data::Data, event::CmdCow}; #[derive(Debug, Default)] pub struct MoveOpt { @@ -12,10 +12,7 @@ pub struct MoveOpt { impl From for MoveOpt { fn from(c: CmdCow) -> Self { - Self { - step: c.first().and_then(|d| d.try_into().ok()).unwrap_or_default(), - in_operating: c.bool("in-operating"), - } + Self { step: c.first().ok().unwrap_or_default(), in_operating: c.bool("in-operating") } } } diff --git a/yazi-parser/src/mgr/cd.rs b/yazi-parser/src/mgr/cd.rs index ba7578a7..d26c3baa 100644 --- a/yazi-parser/src/mgr/cd.rs +++ b/yazi-parser/src/mgr/cd.rs @@ -11,7 +11,7 @@ pub struct CdOpt { impl From for CdOpt { fn from(mut c: CmdCow) -> Self { - let mut target = c.take_first_url().unwrap_or_default(); + let mut target = c.take_first().unwrap_or_default(); if !c.bool("raw") { target = expand_url(target).into(); diff --git a/yazi-parser/src/mgr/copy.rs b/yazi-parser/src/mgr/copy.rs index a47b083e..6468bd17 100644 --- a/yazi-parser/src/mgr/copy.rs +++ b/yazi-parser/src/mgr/copy.rs @@ -1,6 +1,7 @@ -use std::{borrow::Cow, ffi::OsStr, path::Path}; +use std::{borrow::Cow, ffi::OsStr, path::Path, str::FromStr}; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; +use serde::Deserialize; use yazi_shared::{SStr, event::CmdCow}; #[derive(Debug)] @@ -13,8 +14,8 @@ pub struct CopyOpt { impl From for CopyOpt { fn from(mut c: CmdCow) -> Self { Self { - r#type: c.take_first_str().unwrap_or_default(), - separator: c.str("separator").unwrap_or_default().into(), + r#type: c.take_first().unwrap_or_default(), + separator: c.str("separator").parse().unwrap_or_default(), hovered: c.bool("hovered"), } } @@ -29,18 +30,19 @@ impl IntoLua for CopyOpt { } // --- Separator -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Deserialize)] +#[serde(rename_all = "kebab-case")] pub enum CopySeparator { + #[default] Auto, Unix, } -impl From<&str> for CopySeparator { - fn from(value: &str) -> Self { - match value { - "unix" => Self::Unix, - _ => Self::Auto, - } +impl FromStr for CopySeparator { + type Err = serde::de::value::Error; + + fn from_str(s: &str) -> Result { + Self::deserialize(serde::de::value::StrDeserializer::new(s)) } } diff --git a/yazi-parser/src/mgr/download.rs b/yazi-parser/src/mgr/download.rs new file mode 100644 index 00000000..a22c85e1 --- /dev/null +++ b/yazi-parser/src/mgr/download.rs @@ -0,0 +1,20 @@ +use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; +use yazi_shared::{event::CmdCow, url::UrlCow}; + +#[derive(Debug, Default)] +pub struct DownloadOpt { + pub urls: Vec>, + pub open: bool, +} + +impl From for DownloadOpt { + fn from(mut c: CmdCow) -> Self { Self { urls: c.take_seq(), open: c.bool("open") } } +} + +impl FromLua for DownloadOpt { + fn from_lua(_: Value, _: &Lua) -> mlua::Result { Err("unsupported".into_lua_err()) } +} + +impl IntoLua for DownloadOpt { + fn into_lua(self, _: &Lua) -> mlua::Result { Err("unsupported".into_lua_err()) } +} diff --git a/yazi-parser/src/mgr/escape.rs b/yazi-parser/src/mgr/escape.rs index c4457362..145b0390 100644 --- a/yazi-parser/src/mgr/escape.rs +++ b/yazi-parser/src/mgr/escape.rs @@ -16,7 +16,7 @@ bitflags! { impl From for EscapeOpt { fn from(c: CmdCow) -> Self { c.args.iter().fold(Self::empty(), |acc, (k, v)| { - match (k.as_str().unwrap_or(""), v.as_bool().unwrap_or(false)) { + match (k.as_str().unwrap_or(""), v.try_into().unwrap_or(false)) { ("all", true) => Self::all(), ("find", true) => acc | Self::FIND, ("visual", true) => acc | Self::VISUAL, diff --git a/yazi-parser/src/mgr/filter.rs b/yazi-parser/src/mgr/filter.rs index b84b16cb..a6f693a3 100644 --- a/yazi-parser/src/mgr/filter.rs +++ b/yazi-parser/src/mgr/filter.rs @@ -18,7 +18,7 @@ impl TryFrom for FilterOpt { } Ok(Self { - query: c.take_first_str().unwrap_or_default(), + query: c.take_first().unwrap_or_default(), case: FilterCase::from(&*c), done: c.bool("done"), }) diff --git a/yazi-parser/src/mgr/find_do.rs b/yazi-parser/src/mgr/find_do.rs index d52bf5fc..28438523 100644 --- a/yazi-parser/src/mgr/find_do.rs +++ b/yazi-parser/src/mgr/find_do.rs @@ -18,7 +18,7 @@ impl TryFrom for FindDoOpt { return opt; } - let Some(query) = c.take_first_str() else { + let Ok(query) = c.take_first() else { bail!("'query' is required for FindDoOpt"); }; diff --git a/yazi-parser/src/mgr/hidden.rs b/yazi-parser/src/mgr/hidden.rs index 99069bc0..36f84d27 100644 --- a/yazi-parser/src/mgr/hidden.rs +++ b/yazi-parser/src/mgr/hidden.rs @@ -13,7 +13,7 @@ impl TryFrom for HiddenOpt { type Error = anyhow::Error; fn try_from(c: CmdCow) -> Result { - Ok(Self { state: c.first_str().map(FromStr::from_str).transpose()?.unwrap_or_default() }) + Ok(Self { state: c.str(0).parse().unwrap_or_default() }) } } diff --git a/yazi-parser/src/mgr/linemode.rs b/yazi-parser/src/mgr/linemode.rs index b37985a5..6c416b89 100644 --- a/yazi-parser/src/mgr/linemode.rs +++ b/yazi-parser/src/mgr/linemode.rs @@ -11,7 +11,7 @@ impl TryFrom for LinemodeOpt { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { - let Some(new) = c.take_first_str() else { + let Ok(new) = c.take_first::() else { bail!("a string argument is required for LinemodeOpt"); }; diff --git a/yazi-parser/src/mgr/mod.rs b/yazi-parser/src/mgr/mod.rs index 59e083df..18a27e70 100644 --- a/yazi-parser/src/mgr/mod.rs +++ b/yazi-parser/src/mgr/mod.rs @@ -3,6 +3,7 @@ yazi_macro::mod_flat!( close copy create + download escape filter find diff --git a/yazi-parser/src/mgr/open.rs b/yazi-parser/src/mgr/open.rs index 552a71d6..95d05397 100644 --- a/yazi-parser/src/mgr/open.rs +++ b/yazi-parser/src/mgr/open.rs @@ -1,15 +1,20 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::CmdCow; +use yazi_shared::{event::CmdCow, url::UrlCow}; -#[derive(Clone, Copy, Debug)] +#[derive(Debug)] pub struct OpenOpt { + pub targets: Vec>, pub interactive: bool, pub hovered: bool, } impl From for OpenOpt { - fn from(c: CmdCow) -> Self { - Self { interactive: c.bool("interactive"), hovered: c.bool("hovered") } + fn from(mut c: CmdCow) -> Self { + Self { + targets: c.take_seq(), + interactive: c.bool("interactive"), + hovered: c.bool("hovered"), + } } } diff --git a/yazi-parser/src/mgr/open_do.rs b/yazi-parser/src/mgr/open_do.rs index eaf55cbc..38c7cc4a 100644 --- a/yazi-parser/src/mgr/open_do.rs +++ b/yazi-parser/src/mgr/open_do.rs @@ -1,11 +1,11 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::{event::CmdCow, url::UrlBuf}; +use yazi_shared::{event::CmdCow, url::{UrlBuf, UrlCow}}; #[derive(Debug, Default)] pub struct OpenDoOpt { pub cwd: UrlBuf, - pub hovered: UrlBuf, - pub targets: Vec<(UrlBuf, &'static str)>, + pub hovered: UrlCow<'static>, + pub targets: Vec>, pub interactive: bool, } diff --git a/yazi-parser/src/mgr/open_with.rs b/yazi-parser/src/mgr/open_with.rs index 300ef569..229adc93 100644 --- a/yazi-parser/src/mgr/open_with.rs +++ b/yazi-parser/src/mgr/open_with.rs @@ -3,13 +3,13 @@ use std::borrow::Cow; use anyhow::anyhow; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; use yazi_config::opener::OpenerRule; -use yazi_shared::{event::CmdCow, url::UrlBuf}; +use yazi_shared::{event::CmdCow, url::{UrlBuf, UrlCow}}; #[derive(Debug)] pub struct OpenWithOpt { pub opener: Cow<'static, OpenerRule>, pub cwd: UrlBuf, - pub targets: Vec, + pub targets: Vec>, } impl TryFrom for OpenWithOpt { diff --git a/yazi-parser/src/mgr/peek.rs b/yazi-parser/src/mgr/peek.rs index d92a4181..881e5376 100644 --- a/yazi-parser/src/mgr/peek.rs +++ b/yazi-parser/src/mgr/peek.rs @@ -1,5 +1,5 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::{event::{CmdCow, Data}, url::UrlCow}; +use yazi_shared::{event::CmdCow, url::UrlCow}; #[derive(Debug, Default)] pub struct PeekOpt { @@ -12,9 +12,9 @@ pub struct PeekOpt { impl From for PeekOpt { fn from(mut c: CmdCow) -> Self { Self { - skip: c.first().and_then(Data::as_usize), + skip: c.first().ok(), force: c.bool("force"), - only_if: c.take_url("only-if"), + only_if: c.take("only-if").ok(), upper_bound: c.bool("upper-bound"), } } diff --git a/yazi-parser/src/mgr/quit.rs b/yazi-parser/src/mgr/quit.rs index e2c9ef9c..057b40e8 100644 --- a/yazi-parser/src/mgr/quit.rs +++ b/yazi-parser/src/mgr/quit.rs @@ -1,6 +1,6 @@ use mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value}; use serde::{Deserialize, Serialize}; -use yazi_shared::event::{CmdCow, Data, EventQuit}; +use yazi_shared::event::{CmdCow, EventQuit}; #[derive(Debug, Default, Deserialize, Serialize)] pub struct QuitOpt { @@ -10,10 +10,7 @@ pub struct QuitOpt { impl From for QuitOpt { fn from(c: CmdCow) -> Self { - Self { - code: c.get("code").and_then(Data::as_i32).unwrap_or_default(), - no_cwd_file: c.bool("no-cwd-file"), - } + Self { code: c.get("code").unwrap_or_default(), no_cwd_file: c.bool("no-cwd-file") } } } diff --git a/yazi-parser/src/mgr/rename.rs b/yazi-parser/src/mgr/rename.rs index 79b713f1..93830bfa 100644 --- a/yazi-parser/src/mgr/rename.rs +++ b/yazi-parser/src/mgr/rename.rs @@ -14,8 +14,8 @@ impl From for RenameOpt { Self { hovered: c.bool("hovered"), force: c.bool("force"), - empty: c.take_str("empty").unwrap_or_default(), - cursor: c.take_str("cursor").unwrap_or_default(), + empty: c.take("empty").unwrap_or_default(), + cursor: c.take("cursor").unwrap_or_default(), } } } diff --git a/yazi-parser/src/mgr/reveal.rs b/yazi-parser/src/mgr/reveal.rs index a3fe73f8..8b790982 100644 --- a/yazi-parser/src/mgr/reveal.rs +++ b/yazi-parser/src/mgr/reveal.rs @@ -13,7 +13,7 @@ pub struct RevealOpt { impl From for RevealOpt { fn from(mut c: CmdCow) -> Self { - let mut target = c.take_first_url().unwrap_or_default(); + let mut target = c.take_first().unwrap_or_default(); if !c.bool("raw") { target = expand_url(target).into(); diff --git a/yazi-parser/src/mgr/search.rs b/yazi-parser/src/mgr/search.rs index ffb7f1ec..ffef434e 100644 --- a/yazi-parser/src/mgr/search.rs +++ b/yazi-parser/src/mgr/search.rs @@ -1,5 +1,8 @@ +use std::str::FromStr; + use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; +use serde::Deserialize; use yazi_shared::{SStr, event::CmdCow}; #[derive(Debug)] @@ -15,13 +18,13 @@ impl TryFrom for SearchOpt { fn try_from(mut c: CmdCow) -> Result { // TODO: remove this - let (via, subject) = if let Some(s) = c.take_str("via") { - (s.as_ref().into(), c.take_first_str().unwrap_or_default()) + let (via, subject) = if let Ok(s) = c.get("via") { + (str::parse(s)?, c.take_first().unwrap_or_default()) } else { - (c.take_first_str().unwrap_or_default().as_ref().into(), "".into()) + (c.str(0).parse()?, "".into()) }; - let Ok(args) = yazi_shared::shell::split_unix(c.str("args").unwrap_or_default(), false) else { + let Ok(args) = yazi_shared::shell::split_unix(c.str("args"), false) else { bail!("Invalid 'args' argument in SearchOpt"); }; @@ -30,7 +33,7 @@ impl TryFrom for SearchOpt { subject, // TODO: use second positional argument instead of `args` parameter args: args.0, - args_raw: c.take_str("args").unwrap_or_default(), + args_raw: c.take("args").unwrap_or_default(), }) } } @@ -44,20 +47,19 @@ impl IntoLua for SearchOpt { } // Via -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "kebab-case")] pub enum SearchOptVia { Rg, Rga, Fd, } -impl From<&str> for SearchOptVia { - fn from(value: &str) -> Self { - match value { - "rg" => Self::Rg, - "rga" => Self::Rga, - _ => Self::Fd, - } +impl FromStr for SearchOptVia { + type Err = serde::de::value::Error; + + fn from_str(s: &str) -> Result { + Self::deserialize(serde::de::value::StrDeserializer::new(s)) } } diff --git a/yazi-parser/src/mgr/seek.rs b/yazi-parser/src/mgr/seek.rs index f64d36cb..bc8183da 100644 --- a/yazi-parser/src/mgr/seek.rs +++ b/yazi-parser/src/mgr/seek.rs @@ -1,5 +1,5 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::event::CmdCow; #[derive(Debug)] pub struct SeekOpt { @@ -7,7 +7,7 @@ pub struct SeekOpt { } impl From for SeekOpt { - fn from(c: CmdCow) -> Self { Self { units: c.first().and_then(Data::as_i16).unwrap_or(0) } } + fn from(c: CmdCow) -> Self { Self { units: c.first().unwrap_or(0) } } } impl FromLua for SeekOpt { diff --git a/yazi-parser/src/mgr/shell.rs b/yazi-parser/src/mgr/shell.rs index f295621f..d4fcebc1 100644 --- a/yazi-parser/src/mgr/shell.rs +++ b/yazi-parser/src/mgr/shell.rs @@ -1,6 +1,6 @@ use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::{SStr, event::{CmdCow, Data}, url::UrlCow}; +use yazi_shared::{SStr, event::CmdCow, url::UrlCow}; #[derive(Debug)] pub struct ShellOpt { @@ -19,14 +19,14 @@ impl TryFrom for ShellOpt { fn try_from(mut c: CmdCow) -> Result { let me = Self { - run: c.take_first_str().unwrap_or_default(), - cwd: c.take_url("cwd"), + run: c.take_first().unwrap_or_default(), + cwd: c.take("cwd").ok(), block: c.bool("block"), orphan: c.bool("orphan"), interactive: c.bool("interactive"), - cursor: c.get("cursor").and_then(Data::as_usize), + cursor: c.get("cursor").ok(), }; if me.cursor.is_some_and(|c| c > me.run.chars().count()) { diff --git a/yazi-parser/src/mgr/sort.rs b/yazi-parser/src/mgr/sort.rs index 93f35934..0e411696 100644 --- a/yazi-parser/src/mgr/sort.rs +++ b/yazi-parser/src/mgr/sort.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; use yazi_fs::SortBy; use yazi_shared::event::CmdCow; @@ -18,11 +16,11 @@ impl TryFrom for SortOpt { fn try_from(c: CmdCow) -> Result { Ok(Self { - by: c.first_str().map(SortBy::from_str).transpose()?, - reverse: c.maybe_bool("reverse"), - dir_first: c.maybe_bool("dir-first"), - sensitive: c.maybe_bool("sensitive"), - translit: c.maybe_bool("translit"), + by: c.first().ok().map(str::parse).transpose()?, + reverse: c.get("reverse").ok(), + dir_first: c.get("dir-first").ok(), + sensitive: c.get("sensitive").ok(), + translit: c.get("translit").ok(), }) } } diff --git a/yazi-parser/src/mgr/spot.rs b/yazi-parser/src/mgr/spot.rs index 6a825b50..02591edf 100644 --- a/yazi-parser/src/mgr/spot.rs +++ b/yazi-parser/src/mgr/spot.rs @@ -1,5 +1,5 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::event::CmdCow; #[derive(Debug, Default)] pub struct SpotOpt { @@ -7,7 +7,7 @@ pub struct SpotOpt { } impl From for SpotOpt { - fn from(c: CmdCow) -> Self { Self { skip: c.get("skip").and_then(Data::as_usize) } } + fn from(c: CmdCow) -> Self { Self { skip: c.get("skip").ok() } } } impl From for SpotOpt { diff --git a/yazi-parser/src/mgr/tab_close.rs b/yazi-parser/src/mgr/tab_close.rs index 9a482821..da54de94 100644 --- a/yazi-parser/src/mgr/tab_close.rs +++ b/yazi-parser/src/mgr/tab_close.rs @@ -1,5 +1,5 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::event::CmdCow; #[derive(Debug)] pub struct TabCloseOpt { @@ -7,7 +7,7 @@ pub struct TabCloseOpt { } impl From for TabCloseOpt { - fn from(c: CmdCow) -> Self { Self { idx: c.first().and_then(Data::as_usize).unwrap_or(0) } } + fn from(c: CmdCow) -> Self { Self { idx: c.first().unwrap_or(0) } } } impl From for TabCloseOpt { diff --git a/yazi-parser/src/mgr/tab_create.rs b/yazi-parser/src/mgr/tab_create.rs index 10f7ce17..f1bc2b13 100644 --- a/yazi-parser/src/mgr/tab_create.rs +++ b/yazi-parser/src/mgr/tab_create.rs @@ -13,7 +13,7 @@ impl From for TabCreateOpt { if c.bool("current") { return Self { wd: None }; } - let Some(mut wd) = c.take_first_url() else { + let Ok(mut wd) = c.take_first() else { return Self { wd: Some(UrlCow::from(&BOOT.cwds[0])) }; }; if !c.bool("raw") { diff --git a/yazi-parser/src/mgr/tab_switch.rs b/yazi-parser/src/mgr/tab_switch.rs index 5d923e98..f6652330 100644 --- a/yazi-parser/src/mgr/tab_switch.rs +++ b/yazi-parser/src/mgr/tab_switch.rs @@ -1,5 +1,5 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::event::CmdCow; #[derive(Debug)] pub struct TabSwitchOpt { @@ -8,9 +8,7 @@ pub struct TabSwitchOpt { } impl From for TabSwitchOpt { - fn from(c: CmdCow) -> Self { - Self { step: c.first().and_then(Data::as_isize).unwrap_or(0), relative: c.bool("relative") } - } + fn from(c: CmdCow) -> Self { Self { step: c.first().unwrap_or(0), relative: c.bool("relative") } } } impl FromLua for TabSwitchOpt { diff --git a/yazi-parser/src/mgr/toggle.rs b/yazi-parser/src/mgr/toggle.rs index f01a23e3..585c80c2 100644 --- a/yazi-parser/src/mgr/toggle.rs +++ b/yazi-parser/src/mgr/toggle.rs @@ -10,10 +10,10 @@ pub struct ToggleOpt { impl From for ToggleOpt { fn from(mut c: CmdCow) -> Self { Self { - url: c.take_first_url(), - state: match c.str("state") { - Some("on") => Some(true), - Some("off") => Some(false), + url: c.take_first().ok(), + state: match c.get("state") { + Ok("on") => Some(true), + Ok("off") => Some(false), _ => None, }, } diff --git a/yazi-parser/src/mgr/toggle_all.rs b/yazi-parser/src/mgr/toggle_all.rs index 9cebbeae..6ccd8e10 100644 --- a/yazi-parser/src/mgr/toggle_all.rs +++ b/yazi-parser/src/mgr/toggle_all.rs @@ -9,19 +9,11 @@ pub struct ToggleAllOpt { impl From for ToggleAllOpt { fn from(mut c: CmdCow) -> Self { - let mut urls = Vec::with_capacity(c.len()); - for i in 0..c.len() { - match c.take_url(i) { - Some(url) => urls.push(url), - None => break, - } - } - Self { - urls, - state: match c.str("state") { - Some("on") => Some(true), - Some("off") => Some(false), + urls: c.take_seq(), + state: match c.get("state") { + Ok("on") => Some(true), + Ok("off") => Some(false), _ => None, }, } diff --git a/yazi-parser/src/mgr/update_mimes.rs b/yazi-parser/src/mgr/update_mimes.rs index fc159f84..7758e8e7 100644 --- a/yazi-parser/src/mgr/update_mimes.rs +++ b/yazi-parser/src/mgr/update_mimes.rs @@ -1,7 +1,7 @@ use anyhow::bail; use hashbrown::HashMap; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::{CmdCow, Data, DataKey}; +use yazi_shared::{data::{Data, DataKey}, event::CmdCow}; #[derive(Debug)] pub struct UpdateMimesOpt { @@ -12,7 +12,7 @@ impl TryFrom for UpdateMimesOpt { type Error = anyhow::Error; fn try_from(mut c: CmdCow) -> Result { - let Some(updates) = c.try_take("updates").and_then(Data::into_dict) else { + let Ok(updates) = c.take("updates") else { bail!("Invalid 'updates' argument in UpdateMimesOpt"); }; diff --git a/yazi-parser/src/mgr/update_paged.rs b/yazi-parser/src/mgr/update_paged.rs index 85f793a5..e943e7e2 100644 --- a/yazi-parser/src/mgr/update_paged.rs +++ b/yazi-parser/src/mgr/update_paged.rs @@ -1,5 +1,5 @@ use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::{event::{CmdCow, Data}, url::UrlCow}; +use yazi_shared::{event::CmdCow, url::UrlCow}; #[derive(Debug, Default)] pub struct UpdatePagedOpt { @@ -8,9 +8,7 @@ pub struct UpdatePagedOpt { } impl From for UpdatePagedOpt { - fn from(mut c: CmdCow) -> Self { - Self { page: c.first().and_then(Data::as_usize), only_if: c.take_url("only-if") } - } + fn from(mut c: CmdCow) -> Self { Self { page: c.first().ok(), only_if: c.take("only-if").ok() } } } impl From<()> for UpdatePagedOpt { diff --git a/yazi-parser/src/notify/tick.rs b/yazi-parser/src/notify/tick.rs index 771fd72a..ade39d53 100644 --- a/yazi-parser/src/notify/tick.rs +++ b/yazi-parser/src/notify/tick.rs @@ -2,7 +2,7 @@ use std::time::Duration; use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::event::CmdCow; #[derive(Debug)] pub struct TickOpt { @@ -13,7 +13,7 @@ impl TryFrom for TickOpt { type Error = anyhow::Error; fn try_from(c: CmdCow) -> Result { - let Some(interval) = c.first().and_then(Data::as_f64) else { + let Ok(interval) = c.first() else { bail!("Invalid 'interval' argument in TickOpt"); }; diff --git a/yazi-parser/src/spot/copy.rs b/yazi-parser/src/spot/copy.rs index 2ebcfb87..f5799fef 100644 --- a/yazi-parser/src/spot/copy.rs +++ b/yazi-parser/src/spot/copy.rs @@ -7,7 +7,7 @@ pub struct CopyOpt { } impl From for CopyOpt { - fn from(mut c: CmdCow) -> Self { Self { r#type: c.take_first_str().unwrap_or_default() } } + fn from(mut c: CmdCow) -> Self { Self { r#type: c.take_first().unwrap_or_default() } } } impl FromLua for CopyOpt { diff --git a/yazi-parser/src/step.rs b/yazi-parser/src/step.rs index ee522d48..a0c195fd 100644 --- a/yazi-parser/src/step.rs +++ b/yazi-parser/src/step.rs @@ -1,6 +1,6 @@ use std::{num::ParseIntError, str::FromStr}; -use yazi_shared::event::Data; +use yazi_shared::data::Data; #[derive(Clone, Copy, Debug)] pub enum Step { diff --git a/yazi-parser/src/tasks/process_exec.rs b/yazi-parser/src/tasks/process_exec.rs index 45157f55..e6cf3325 100644 --- a/yazi-parser/src/tasks/process_exec.rs +++ b/yazi-parser/src/tasks/process_exec.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, ffi::OsString}; +use std::{borrow::Cow, ffi::OsStr}; use anyhow::anyhow; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; @@ -11,7 +11,7 @@ use yazi_shared::{event::CmdCow, url::UrlBuf}; pub struct ProcessExecOpt { pub cwd: UrlBuf, pub opener: Cow<'static, OpenerRule>, - pub args: Vec, + pub args: Vec>, pub done: Option>, } diff --git a/yazi-parser/src/which/callback.rs b/yazi-parser/src/which/callback.rs index b5818429..61f5a4e4 100644 --- a/yazi-parser/src/which/callback.rs +++ b/yazi-parser/src/which/callback.rs @@ -1,7 +1,7 @@ use anyhow::bail; use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; use tokio::sync::mpsc; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::event::CmdCow; #[derive(Debug)] pub struct CallbackOpt { @@ -17,7 +17,7 @@ impl TryFrom for CallbackOpt { bail!("Invalid 'tx' argument in CallbackOpt"); }; - let Some(idx) = c.first().and_then(Data::as_usize) else { + let Ok(idx) = c.first() else { bail!("Invalid 'idx' argument in CallbackOpt"); }; diff --git a/yazi-plugin/preset/components/current.lua b/yazi-plugin/preset/components/current.lua index 15fb615b..d8364d90 100644 --- a/yazi-plugin/preset/components/current.lua +++ b/yazi-plugin/preset/components/current.lua @@ -20,7 +20,7 @@ function Current:empty() end return { - ui.Line(s):area(self._area):align(ui.Align.CENTER), + ui.Text(s):area(self._area):align(ui.Align.CENTER):wrap(ui.Wrap.YES), } end diff --git a/yazi-plugin/preset/plugins/file.lua b/yazi-plugin/preset/plugins/file.lua index 1399f474..f1663260 100644 --- a/yazi-plugin/preset/plugins/file.lua +++ b/yazi-plugin/preset/plugins/file.lua @@ -30,11 +30,11 @@ function M:spot(job) end function M:spot_base(job) - local url, cha = job.file.url, job.file.cha - local spotter = rt.plugin.spotter(url, job.mime) - local previewer = rt.plugin.previewer(url, job.mime) + local cha = job.file.cha + local spotter = rt.plugin.spotter(job.file, job.mime) + local previewer = rt.plugin.previewer(job.file, job.mime) local fetchers = rt.plugin.fetchers(job.file, job.mime) - local preloaders = rt.plugin.preloaders(url, job.mime) + local preloaders = rt.plugin.preloaders(job.file, job.mime) for i, v in ipairs(fetchers) do fetchers[i] = v.cmd diff --git a/yazi-plugin/preset/plugins/folder.lua b/yazi-plugin/preset/plugins/folder.lua index fb3d2dcd..91ecf720 100644 --- a/yazi-plugin/preset/plugins/folder.lua +++ b/yazi-plugin/preset/plugins/folder.lua @@ -18,7 +18,7 @@ function M:peek(job) if #folder.files == 0 then local done, err = folder.stage() local s = not done and "Loading..." or not err and "No items" or string.format("Error: %s", err) - return ya.preview_widget(job, ui.Line(s):area(job.area):align(ui.Align.CENTER)) + return ya.preview_widget(job, ui.Text(s):area(job.area):align(ui.Align.CENTER):wrap(ui.Wrap.YES)) end local items = {} diff --git a/yazi-plugin/preset/plugins/mime-dir.lua b/yazi-plugin/preset/plugins/mime-dir.lua new file mode 100644 index 00000000..7ee392cf --- /dev/null +++ b/yazi-plugin/preset/plugins/mime-dir.lua @@ -0,0 +1,11 @@ +local function fetch(_, job) + local updates = {} + for _, file in ipairs(job.files) do + updates[file.url] = "folder/local" + end + + ya.emit("update_mimes", { updates = updates }) + return true +end + +return { fetch = fetch } diff --git a/yazi-plugin/preset/plugins/mime-file.lua b/yazi-plugin/preset/plugins/mime-file.lua new file mode 100644 index 00000000..4c7f45ef --- /dev/null +++ b/yazi-plugin/preset/plugins/mime-file.lua @@ -0,0 +1,83 @@ +-- stylua: ignore +local TYPE_PATS = { "text", "image", "video", "application", "audio", "font", "inode", "message", "model", "vector", "biosig", "chemical", "rinex", "x%-epoc" } + +local M = {} + +local function match_mimetype(line) + for _, pat in ipairs(TYPE_PATS) do + local typ, sub = line:match(string.format("(%s/)([+-.a-zA-Z0-9]+)%%s+$", pat)) + if not sub then + elseif line:find(typ .. sub, 1, true) == 1 then + return typ:gsub("^x%-", "", 1) .. sub:gsub("^x%-", "", 1):gsub("^vnd%.", "", 1) + else + return nil, true + end + end +end + +local function miss_cache(cache, line) + if line:match("^cannot open `.+' %(No such file or directory%)%s+$") then + return true + else + local _, err = fs.cha(Url(cache)) + return err and err.code == 2 + end +end + +function M:fetch(job) + local paths, origins = {}, {} + for i, file in ipairs(job.files) do + if file.cache then + paths[i], origins[i] = tostring(file.cache), tostring(file.url) + else + paths[i] = tostring(file.url) + end + end + + local cmd = os.getenv("YAZI_FILE_ONE") or "file" + local child, err = Command(cmd):arg({ "-bL", "--mime-type", "--" }):arg(paths):stdout(Command.PIPED):spawn() + if not child then + return true, Err("Failed to start `%s`, error: %s", cmd, err) + end + + local updates, last = {}, ya.time() + local flush = function(force) + if not force and ya.time() - last < 0.3 then + return + end + if next(updates) then + ya.emit("update_mimes", { updates = updates }) + updates, last = {}, ya.time() + end + end + + local i, state, match, ignore = 1, {}, nil, nil + repeat + local line, event = child:read_line_with { timeout = 300 } + if event == 3 then + flush(true) + goto continue + elseif event ~= 0 then + break + end + + match, ignore = match_mimetype(line) + if match then + updates[origins[i] or paths[i]], state[i], i = match, true, i + 1 + flush(false) + elseif ignore then + goto continue + elseif origins[i] and miss_cache(paths[i], line) then + updates[origins[i]], state[i], i = "vfs/todo", true, i + 1 + flush(false) + else + state[i], i = false, i + 1 + end + ::continue:: + until i > #paths + + flush(true) + return state +end + +return M diff --git a/yazi-plugin/preset/plugins/mime.lua b/yazi-plugin/preset/plugins/mime.lua index 4c7f45ef..e9ac3634 100644 --- a/yazi-plugin/preset/plugins/mime.lua +++ b/yazi-plugin/preset/plugins/mime.lua @@ -1,83 +1,12 @@ --- stylua: ignore -local TYPE_PATS = { "text", "image", "video", "application", "audio", "font", "inode", "message", "model", "vector", "biosig", "chemical", "rinex", "x%-epoc" } +local function fetch(_, job) + ya.notify { + title = "Deprecated plugin", + content = "The `mime` fetcher is deprecated, use `mime.file` instead in your `yazi.toml`\n\nSee https://github.com/sxyazi/yazi/pull/3222 for more details.", + timeout = 15, + level = "warn", + } -local M = {} - -local function match_mimetype(line) - for _, pat in ipairs(TYPE_PATS) do - local typ, sub = line:match(string.format("(%s/)([+-.a-zA-Z0-9]+)%%s+$", pat)) - if not sub then - elseif line:find(typ .. sub, 1, true) == 1 then - return typ:gsub("^x%-", "", 1) .. sub:gsub("^x%-", "", 1):gsub("^vnd%.", "", 1) - else - return nil, true - end - end + return require("mime.file"):fetch(job) end -local function miss_cache(cache, line) - if line:match("^cannot open `.+' %(No such file or directory%)%s+$") then - return true - else - local _, err = fs.cha(Url(cache)) - return err and err.code == 2 - end -end - -function M:fetch(job) - local paths, origins = {}, {} - for i, file in ipairs(job.files) do - if file.cache then - paths[i], origins[i] = tostring(file.cache), tostring(file.url) - else - paths[i] = tostring(file.url) - end - end - - local cmd = os.getenv("YAZI_FILE_ONE") or "file" - local child, err = Command(cmd):arg({ "-bL", "--mime-type", "--" }):arg(paths):stdout(Command.PIPED):spawn() - if not child then - return true, Err("Failed to start `%s`, error: %s", cmd, err) - end - - local updates, last = {}, ya.time() - local flush = function(force) - if not force and ya.time() - last < 0.3 then - return - end - if next(updates) then - ya.emit("update_mimes", { updates = updates }) - updates, last = {}, ya.time() - end - end - - local i, state, match, ignore = 1, {}, nil, nil - repeat - local line, event = child:read_line_with { timeout = 300 } - if event == 3 then - flush(true) - goto continue - elseif event ~= 0 then - break - end - - match, ignore = match_mimetype(line) - if match then - updates[origins[i] or paths[i]], state[i], i = match, true, i + 1 - flush(false) - elseif ignore then - goto continue - elseif origins[i] and miss_cache(paths[i], line) then - updates[origins[i]], state[i], i = "vfs/todo", true, i + 1 - flush(false) - else - state[i], i = false, i + 1 - end - ::continue:: - until i > #paths - - flush(true) - return state -end - -return M +return { fetch = fetch } diff --git a/yazi-plugin/src/loader/loader.rs b/yazi-plugin/src/loader/loader.rs index 9d5946e2..8aa1d6ed 100644 --- a/yazi-plugin/src/loader/loader.rs +++ b/yazi-plugin/src/loader/loader.rs @@ -38,7 +38,9 @@ impl Default for Loader { ("image".to_owned(), preset!("plugins/image").into()), ("json".to_owned(), preset!("plugins/json").into()), ("magick".to_owned(), preset!("plugins/magick").into()), - ("mime".to_owned(), preset!("plugins/mime").into()), + ("mime".to_owned(), preset!("plugins/mime").into()), // TODO: remove this + ("mime.dir".to_owned(), preset!("plugins/mime-dir").into()), + ("mime.file".to_owned(), preset!("plugins/mime-file").into()), ("noop".to_owned(), preset!("plugins/noop").into()), ("pdf".to_owned(), preset!("plugins/pdf").into()), ("session".to_owned(), preset!("plugins/session").into()), diff --git a/yazi-plugin/src/runtime/plugin.rs b/yazi-plugin/src/runtime/plugin.rs index 09203648..3978e6cc 100644 --- a/yazi-plugin/src/runtime/plugin.rs +++ b/yazi-plugin/src/runtime/plugin.rs @@ -1,5 +1,5 @@ use mlua::{Function, IntoLua, Lua, UserData, Value}; -use yazi_binding::{Composer, ComposerGet, ComposerSet, FileRef, UrlRef, cached_field}; +use yazi_binding::{Composer, ComposerGet, ComposerSet, FileRef, cached_field}; use yazi_config::YAZI; pub(super) fn plugin() -> Composer { @@ -21,25 +21,25 @@ pub(super) fn plugin() -> Composer { fn fetchers(lua: &Lua) -> mlua::Result { lua.create_function(|lua, (file, mime): (FileRef, mlua::String)| { - lua.create_sequence_from(YAZI.plugin.fetchers(&file.url, &mime.to_str()?).map(Fetcher::new)) + lua.create_sequence_from(YAZI.plugin.fetchers(&file, &mime.to_str()?).map(Fetcher::new)) }) } fn spotter(lua: &Lua) -> mlua::Result { - lua.create_function(|_, (url, mime): (UrlRef, mlua::String)| { - Ok(YAZI.plugin.spotter(&url, &mime.to_str()?).map(Spotter::new)) + lua.create_function(|_, (file, mime): (FileRef, mlua::String)| { + Ok(YAZI.plugin.spotter(&file, &mime.to_str()?).map(Spotter::new)) }) } fn preloaders(lua: &Lua) -> mlua::Result { - lua.create_function(|lua, (url, mime): (UrlRef, mlua::String)| { - lua.create_sequence_from(YAZI.plugin.preloaders(&url, &mime.to_str()?).map(Preloader::new)) + lua.create_function(|lua, (file, mime): (FileRef, mlua::String)| { + lua.create_sequence_from(YAZI.plugin.preloaders(&file, &mime.to_str()?).map(Preloader::new)) }) } fn previewer(lua: &Lua) -> mlua::Result { - lua.create_function(|_, (url, mime): (UrlRef, mlua::String)| { - Ok(YAZI.plugin.previewer(&url, &mime.to_str()?).map(Previewer::new)) + lua.create_function(|_, (file, mime): (FileRef, mlua::String)| { + Ok(YAZI.plugin.previewer(&file, &mime.to_str()?).map(Previewer::new)) }) } diff --git a/yazi-plugin/src/utils/sync.rs b/yazi-plugin/src/utils/sync.rs index 37382129..ec689459 100644 --- a/yazi-plugin/src/utils/sync.rs +++ b/yazi-plugin/src/utils/sync.rs @@ -6,7 +6,7 @@ use yazi_binding::{runtime, runtime_mut}; use yazi_dds::Sendable; use yazi_parser::app::{PluginCallback, PluginOpt}; use yazi_proxy::AppProxy; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use super::Utils; use crate::{bindings::{MpscRx, MpscTx, MpscUnboundedRx, MpscUnboundedTx, OneshotRx, OneshotTx}, loader::LOADER}; diff --git a/yazi-proxy/src/tasks.rs b/yazi-proxy/src/tasks.rs index a74e5af8..c05411e9 100644 --- a/yazi-proxy/src/tasks.rs +++ b/yazi-proxy/src/tasks.rs @@ -1,19 +1,23 @@ -use std::{borrow::Cow, ffi::OsString}; +use std::{borrow::Cow, ffi::OsStr}; use tokio::sync::oneshot; use yazi_config::opener::OpenerRule; use yazi_macro::{emit, relay}; use yazi_parser::{mgr::OpenWithOpt, tasks::ProcessExecOpt}; -use yazi_shared::url::UrlBuf; +use yazi_shared::url::{UrlBuf, UrlCow}; pub struct TasksProxy; impl TasksProxy { - pub fn open_with(opener: Cow<'static, OpenerRule>, cwd: UrlBuf, targets: Vec) { + pub fn open_with(opener: Cow<'static, OpenerRule>, cwd: UrlBuf, targets: Vec>) { emit!(Call(relay!(tasks:open_with).with_any("option", OpenWithOpt { opener, cwd, targets }))); } - pub async fn process_exec(opener: Cow<'static, OpenerRule>, cwd: UrlBuf, args: Vec) { + pub async fn process_exec( + opener: Cow<'static, OpenerRule>, + cwd: UrlBuf, + args: Vec>, + ) { let (tx, rx) = oneshot::channel(); emit!(Call(relay!(tasks:process_exec).with_any("option", ProcessExecOpt { cwd, diff --git a/yazi-scheduler/src/file/file.rs b/yazi-scheduler/src/file/file.rs index 733ad83d..a7722175 100644 --- a/yazi-scheduler/src/file/file.rs +++ b/yazi-scheduler/src/file/file.rs @@ -5,6 +5,7 @@ use tokio::{io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc}; use tracing::warn; use yazi_config::YAZI; use yazi_fs::{cha::Cha, ok_or_not_found, path::{path_relative_to, skip_url}, provider::{DirReader, FileHolder}}; +use yazi_macro::ok_or_not_found; use yazi_shared::url::{Url, UrlBuf, UrlCow}; use yazi_vfs::{VfsCha, copy_with_progress, maybe_exists, provider::{self, DirEntry}}; @@ -94,7 +95,7 @@ impl File { } pub(crate) async fn paste_do(&self, mut task: FileInPaste) -> Result<(), FileOutPasteDo> { - ok_or_not_found(provider::remove_file(&task.to).await)?; + ok_or_not_found!(provider::remove_file(&task.to).await); let mut it = copy_with_progress(&task.from, &task.to, task.cha.unwrap()); while let Some(res) = it.recv().await { @@ -132,13 +133,11 @@ impl File { pub(crate) async fn link_do(&self, task: FileInLink) -> Result<(), FileOutLink> { let src: Cow<_> = if task.resolve { - match provider::read_link(&task.from).await { - Ok(p) => p.into(), - Err(e) if e.kind() == NotFound => { - return Ok(self.ops.out(task.id, FileOutLink::Succ)); - } - Err(e) => Err(e)?, - } + ok_or_not_found!( + provider::read_link(&task.from).await, + return Ok(self.ops.out(task.id, FileOutLink::Succ)) + ) + .into() } else if task.from.scheme.covariant(&task.to.scheme) { task.from.loc.as_path().into() } else { @@ -151,7 +150,7 @@ impl File { src }; - ok_or_not_found(provider::remove_file(&task.to).await)?; + ok_or_not_found!(provider::remove_file(&task.to).await); provider::symlink(&src, &task.to, async || { Ok(match task.cha { Some(cha) => cha.is_dir(), @@ -231,8 +230,8 @@ impl File { UrlCow::from(&task.from) }; - ok_or_not_found(provider::remove_file(&task.to).await)?; - ok_or_not_found(provider::hard_link(&src, &task.to).await)?; + ok_or_not_found!(provider::remove_file(&task.to).await); + ok_or_not_found!(provider::hard_link(&src, &task.to).await); Ok(self.ops.out(task.id, FileOutHardlinkDo::Succ)) } diff --git a/yazi-scheduler/src/process/in.rs b/yazi-scheduler/src/process/in.rs index 20667213..7f6d25b9 100644 --- a/yazi-scheduler/src/process/in.rs +++ b/yazi-scheduler/src/process/in.rs @@ -1,4 +1,4 @@ -use std::ffi::OsString; +use std::{borrow::Cow, ffi::{OsStr, OsString}}; use tokio::sync::mpsc; use yazi_shared::{Id, url::UrlBuf}; @@ -11,7 +11,7 @@ pub(crate) struct ProcessInBlock { pub(crate) id: Id, pub(crate) cwd: UrlBuf, pub(crate) cmd: OsString, - pub(crate) args: Vec, + pub(crate) args: Vec>, } impl From for ShellOpt { @@ -26,7 +26,7 @@ pub(crate) struct ProcessInOrphan { pub(crate) id: Id, pub(crate) cwd: UrlBuf, pub(crate) cmd: OsString, - pub(crate) args: Vec, + pub(crate) args: Vec>, } impl From for ShellOpt { @@ -41,7 +41,7 @@ pub(crate) struct ProcessInBg { pub(crate) id: Id, pub(crate) cwd: UrlBuf, pub(crate) cmd: OsString, - pub(crate) args: Vec, + pub(crate) args: Vec>, pub(crate) cancel: mpsc::Receiver<()>, } diff --git a/yazi-scheduler/src/process/shell.rs b/yazi-scheduler/src/process/shell.rs index fd33f8c6..81f2b731 100644 --- a/yazi-scheduler/src/process/shell.rs +++ b/yazi-scheduler/src/process/shell.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, ffi::OsString, process::Stdio}; +use std::{borrow::Cow, ffi::{OsStr, OsString}, process::Stdio}; use anyhow::{Result, bail}; use tokio::process::{Child, Command}; @@ -8,7 +8,7 @@ use yazi_shared::url::UrlBuf; pub(crate) struct ShellOpt { pub(crate) cwd: UrlBuf, pub(crate) cmd: OsString, - pub(crate) args: Vec, + pub(crate) args: Vec>, pub(crate) piped: bool, pub(crate) orphan: bool, } @@ -75,7 +75,7 @@ pub(crate) async fn shell(opt: ShellOpt) -> Result { #[cfg(windows)] mod parser { - use std::{ffi::{OsStr, OsString}, iter::Peekable, os::windows::ffi::{EncodeWide, OsStrExt, OsStringExt}}; + use std::{borrow::Cow, ffi::{OsStr, OsString}, iter::Peekable, os::windows::ffi::{EncodeWide, OsStrExt, OsStringExt}}; macro_rules! w { ($c:literal) => { @@ -83,7 +83,7 @@ mod parser { }; } - pub(super) fn parse(cmd: &OsStr, args: &[OsString]) -> OsString { + pub(super) fn parse(cmd: &OsStr, args: &[Cow]) -> OsString { if cmd.len() < 2 { return cmd.to_owned(); } @@ -120,7 +120,7 @@ mod parser { fn visit_percent( mut it: Peekable, buf: &mut Vec, - args: &[OsString], + args: &[Cow], quote: bool, ) -> usize { let Some(c) = it.next().and_then(|c| char::from_u32(c as _)) else { @@ -186,7 +186,7 @@ mod parser { fn parse(cmd: &str, args: &[&str]) -> String { let cmd = OsString::from(cmd); - let args: Vec<_> = args.iter().map(|&s| OsString::from(s)).collect(); + let args: Vec<_> = args.iter().map(|&s| OsString::from(s).into()).collect(); super::parse(&cmd, &args).to_str().unwrap().to_owned() } diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index 73862bfa..35b272dc 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -6,6 +6,7 @@ use parking_lot::Mutex; use tokio::{select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::JoinHandle}; use yazi_config::{YAZI, plugin::{Fetcher, Preloader}}; use yazi_dds::Pump; +use yazi_fs::FsUrl; use yazi_parser::{app::PluginOpt, tasks::ProcessExecOpt}; use yazi_proxy::TasksProxy; use yazi_shared::{Id, Throttle, url::UrlBuf}; @@ -209,6 +210,26 @@ impl Scheduler { self.send_micro(id, LOW, async move { file.trash(FileInTrash { id, target }) }) } + pub fn file_download(&self, from: UrlBuf, done: Option>) { + let mut ongoing = self.ongoing.lock(); + let id = self.ongoing.lock().add::(format!("Download {}", from.display())); + + if let Some(tx) = done { + ongoing.hooks.add_sync(id, move |canceled| _ = tx.send(canceled)); + } + + let Some(to) = from.cache().map(UrlBuf::from) else { + return self + .ops + .out(id, FileOutPaste::Deform("Unable to download non-remote file".to_owned())); + }; + + let file = self.file.clone(); + self.send_micro(id, LOW, async move { + file.paste(FileInPaste { id, from, to, cha: None, cut: false, follow: false, retry: 0 }).await + }); + } + pub fn plugin_micro(&self, opt: PluginOpt) { let id = self.ongoing.lock().add::(format!("Run micro plugin `{}`", opt.id)); @@ -245,6 +266,22 @@ impl Scheduler { }); } + pub async fn fetch_mimetype(&self, targets: Vec) -> bool { + let mut wg = vec![]; + for (fetcher, targets) in YAZI.plugin.mime_fetchers(targets) { + let (tx, rx) = oneshot::channel(); + self.fetch_paged(fetcher, targets, Some(tx)); + wg.push(rx); + } + + for rx in wg { + if rx.await != Ok(true) { + return false; + } + } + true + } + pub fn preload_paged(&self, preloader: &'static Preloader, target: &yazi_fs::File) { let id = self.ongoing.lock().add::(format!("Run preloader `{}`", preloader.run.name)); diff --git a/yazi-shared/src/chars.rs b/yazi-shared/src/chars.rs index 319ae580..f6e7a943 100644 --- a/yazi-shared/src/chars.rs +++ b/yazi-shared/src/chars.rs @@ -1,8 +1,6 @@ use core::str; use std::{borrow::Cow, ffi::OsStr}; -pub const MIME_DIR: &str = "inode/directory"; - #[derive(Clone, Copy, PartialEq, Eq)] pub enum CharKind { Space, diff --git a/yazi-shared/src/data/data.rs b/yazi-shared/src/data/data.rs new file mode 100644 index 00000000..fc8c28ce --- /dev/null +++ b/yazi-shared/src/data/data.rs @@ -0,0 +1,246 @@ +use std::{any::Any, borrow::Cow}; + +use anyhow::{Result, bail}; +use hashbrown::HashMap; +use serde::{Deserialize, Serialize}; + +use crate::{Id, SStr, data::DataKey, url::{UrlBuf, UrlCow, UrnBuf}}; + +// --- Data +#[derive(Debug, Deserialize, Serialize)] +#[serde(untagged)] +pub enum Data { + Nil, + Boolean(bool), + Integer(i64), + Number(f64), + String(SStr), + List(Vec), + Dict(HashMap), + Id(Id), + #[serde(skip_deserializing)] + Url(UrlBuf), + #[serde(skip_deserializing)] + Urn(UrnBuf), + #[serde(skip)] + Bytes(Vec), + #[serde(skip)] + Any(Box), +} + +impl Data { + pub fn as_str(&self) -> Option<&str> { + match self { + Self::String(s) => Some(s), + _ => None, + } + } + + pub fn into_string(self) -> Option { + match self { + Self::String(s) => Some(s), + _ => None, + } + } + + pub fn into_any(self) -> Option { + match self { + Self::Any(b) => b.downcast::().ok().map(|b| *b), + _ => None, + } + } + + // FIXME: find a better name + pub fn into_any2(self) -> Result { + if let Self::Any(b) = self + && let Ok(t) = b.downcast::() + { + Ok(*t) + } else { + bail!("Failed to downcast Data into {}", std::any::type_name::()) + } + } +} + +impl From<()> for Data { + fn from(_: ()) -> Self { Self::Nil } +} + +impl From for Data { + fn from(value: bool) -> Self { Self::Boolean(value) } +} + +impl From for Data { + fn from(value: i32) -> Self { Self::Integer(value as i64) } +} + +impl From for Data { + fn from(value: i64) -> Self { Self::Integer(value) } +} + +impl From for Data { + fn from(value: f64) -> Self { Self::Number(value) } +} + +impl From for Data { + fn from(value: usize) -> Self { Self::Id(value.into()) } +} + +impl From for Data { + fn from(value: String) -> Self { Self::String(Cow::Owned(value)) } +} + +impl From for Data { + fn from(value: SStr) -> Self { Self::String(value) } +} + +impl From for Data { + fn from(value: Id) -> Self { Self::Id(value) } +} + +impl From<&UrlBuf> for Data { + fn from(value: &UrlBuf) -> Self { Self::Url(value.clone()) } +} + +impl From<&str> for Data { + fn from(value: &str) -> Self { Self::String(Cow::Owned(value.to_owned())) } +} + +impl TryFrom<&Data> for bool { + type Error = anyhow::Error; + + fn try_from(value: &Data) -> Result { + match value { + Data::Boolean(b) => Ok(*b), + Data::String(s) if s == "no" => Ok(false), + Data::String(s) if s == "yes" => Ok(true), + _ => bail!("not a boolean"), + } + } +} + +impl<'a> TryFrom<&'a Data> for &'a str { + type Error = anyhow::Error; + + fn try_from(value: &'a Data) -> Result { + match value { + Data::String(s) => Ok(s), + _ => bail!("not a string"), + } + } +} + +impl TryFrom for SStr { + type Error = anyhow::Error; + + fn try_from(value: Data) -> Result { + match value { + Data::String(s) => Ok(s), + _ => bail!("not a string"), + } + } +} + +impl<'a> TryFrom<&'a Data> for Cow<'a, str> { + type Error = anyhow::Error; + + fn try_from(value: &'a Data) -> Result { + match value { + Data::String(s) => Ok(s.as_ref().into()), + _ => bail!("not a string"), + } + } +} + +impl TryFrom for HashMap { + type Error = anyhow::Error; + + fn try_from(value: Data) -> Result { + match value { + Data::Dict(d) => Ok(d), + _ => bail!("not a dict"), + } + } +} + +impl TryFrom<&Data> for HashMap { + type Error = anyhow::Error; + + fn try_from(_: &Data) -> Result { + bail!("cannot take ownership of dict from &Data"); + } +} + +impl TryFrom for UrlCow<'static> { + type Error = anyhow::Error; + + fn try_from(value: Data) -> Result { + match value { + Data::String(s) => s.try_into(), + Data::Url(u) => Ok(u.into()), + Data::Bytes(b) => b.try_into(), + _ => bail!("not a URL"), + } + } +} + +impl<'a> TryFrom<&'a Data> for UrlCow<'a> { + type Error = anyhow::Error; + + fn try_from(value: &'a Data) -> Result { + match value { + Data::String(s) => s.as_ref().try_into(), + Data::Url(u) => Ok(u.into()), + Data::Bytes(b) => b.as_slice().try_into(), + _ => bail!("not a URL"), + } + } +} + +impl PartialEq for Data { + fn eq(&self, other: &bool) -> bool { self.try_into().is_ok_and(|b| *other == b) } +} + +// --- Macros +macro_rules! impl_into_integer { + ($t:ty, $name:ident) => { + impl TryFrom<&Data> for $t { + type Error = anyhow::Error; + + fn try_from(value: &Data) -> Result { + Ok(match value { + Data::Integer(i) => <$t>::try_from(*i)?, + Data::String(s) => s.parse()?, + Data::Id(i) => <$t>::try_from(i.get())?, + _ => bail!("not an integer"), + }) + } + } + }; +} + +macro_rules! impl_into_number { + ($t:ty, $name:ident) => { + impl TryFrom<&Data> for $t { + type Error = anyhow::Error; + + fn try_from(value: &Data) -> Result { + Ok(match value { + Data::Integer(i) if *i == (*i as $t as _) => *i as $t, + Data::Number(n) => <$t>::try_from(*n)?, + Data::String(s) => s.parse()?, + Data::Id(i) if i.0 == (i.0 as $t as _) => i.0 as $t, + _ => bail!("not a number"), + }) + } + } + }; +} + +impl_into_integer!(usize, as_usize); +impl_into_integer!(isize, as_isize); +impl_into_integer!(i16, as_i16); +impl_into_integer!(i32, as_i32); +impl_into_integer!(crate::Id, as_id); + +impl_into_number!(f64, as_f64); diff --git a/yazi-shared/src/data/key.rs b/yazi-shared/src/data/key.rs new file mode 100644 index 00000000..7faa3724 --- /dev/null +++ b/yazi-shared/src/data/key.rs @@ -0,0 +1,82 @@ +use std::borrow::Cow; + +use ordered_float::OrderedFloat; +use serde::{Deserialize, Serialize, de}; + +use crate::{Id, SStr, url::{UrlBuf, UrlCow, UrnBuf}}; + +#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +#[serde(untagged)] +pub enum DataKey { + Nil, + Boolean(bool), + #[serde(deserialize_with = "Self::deserialize_integer")] + Integer(i64), + Number(OrderedFloat), + String(SStr), + Id(Id), + #[serde(skip_deserializing)] + Url(UrlBuf), + #[serde(skip_deserializing)] + Urn(UrnBuf), + #[serde(skip)] + Bytes(Vec), +} + +impl DataKey { + pub fn is_integer(&self) -> bool { matches!(self, Self::Integer(_)) } + + pub fn as_str(&self) -> Option<&str> { + match self { + Self::String(s) => Some(s), + _ => None, + } + } + + pub fn into_url(self) -> Option> { + match self { + Self::String(s) => s.try_into().ok(), + Self::Url(u) => Some(u.into()), + Self::Bytes(b) => b.try_into().ok(), + _ => None, + } + } + + fn deserialize_integer<'de, D>(deserializer: D) -> Result + where + D: de::Deserializer<'de>, + { + struct Visitor; + + impl de::Visitor<'_> for Visitor { + type Value = i64; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("an integer or a string of an integer") + } + + fn visit_i64(self, value: i64) -> Result { Ok(value) } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + value.parse().map_err(de::Error::custom) + } + } + + deserializer.deserialize_any(Visitor) + } +} + +impl From for DataKey { + fn from(value: usize) -> Self { Self::Integer(value as i64) } +} + +impl From<&'static str> for DataKey { + fn from(value: &'static str) -> Self { Self::String(Cow::Borrowed(value)) } +} + +impl From for DataKey { + fn from(value: String) -> Self { Self::String(Cow::Owned(value)) } +} diff --git a/yazi-shared/src/data/mod.rs b/yazi-shared/src/data/mod.rs new file mode 100644 index 00000000..ea06534c --- /dev/null +++ b/yazi-shared/src/data/mod.rs @@ -0,0 +1 @@ +yazi_macro::mod_flat!(data key); diff --git a/yazi-shared/src/event/cmd.rs b/yazi-shared/src/event/cmd.rs index cfabe7c4..2a35eb3c 100644 --- a/yazi-shared/src/event/cmd.rs +++ b/yazi-shared/src/event/cmd.rs @@ -4,8 +4,7 @@ use anyhow::{Result, anyhow, bail}; use hashbrown::HashMap; use serde::{Deserialize, de}; -use super::{Data, DataKey}; -use crate::{Id, Layer, SStr, Source, url::UrlCow}; +use crate::{Layer, SStr, Source, data::{Data, DataKey}}; #[derive(Debug, Default)] pub struct Cmd { @@ -54,23 +53,18 @@ impl Cmd { cmd } - #[inline] fn null() -> Self { Self { name: Cow::Borrowed("null"), ..Default::default() } } - #[inline] pub fn len(&self) -> usize { self.args.len() } - #[inline] pub fn is_empty(&self) -> bool { self.args.is_empty() } // --- With - #[inline] pub fn with(mut self, name: impl Into, value: impl Into) -> Self { self.args.insert(name.into(), value.into()); self } - #[inline] pub fn with_opt(mut self, name: impl Into, value: Option>) -> Self { if let Some(v) = value { self.args.insert(name.into(), v.into()); @@ -78,71 +72,103 @@ impl Cmd { self } - #[inline] pub fn with_any(mut self, name: impl Into, data: impl Any + Send + Sync) -> Self { self.args.insert(name.into(), Data::Any(Box::new(data))); self } // --- Get - #[inline] - pub fn get(&self, name: impl Into) -> Option<&Data> { self.args.get(&name.into()) } + pub fn get<'a, T>(&'a self, name: impl Into) -> Result + where + T: TryFrom<&'a Data>, + T::Error: Into, + { + let name = name.into(); + match self.args.get(&name) { + Some(data) => data.try_into().map_err(Into::into), + None => bail!("argument not found: {:?}", name), + } + } - #[inline] - pub fn str(&self, name: impl Into) -> Option<&str> { self.get(name)?.as_str() } + pub fn str(&self, name: impl Into) -> &str { self.get(name).unwrap_or_default() } - #[inline] - pub fn bool(&self, name: impl Into) -> bool { self.maybe_bool(name).unwrap_or(false) } + pub fn bool(&self, name: impl Into) -> bool { self.get(name).unwrap_or(false) } - #[inline] - pub fn maybe_bool(&self, name: impl Into) -> Option { self.get(name)?.as_bool() } + pub fn first<'a, T>(&'a self) -> Result + where + T: TryFrom<&'a Data>, + T::Error: Into, + { + self.get(0).map_err(Into::into) + } - #[inline] - pub fn id(&self, name: impl Into) -> Option { self.get(name)?.as_id() } + pub fn second<'a, T>(&'a self) -> Result + where + T: TryFrom<&'a Data>, + T::Error: Into, + { + self.get(1).map_err(Into::into) + } - #[inline] - pub fn url(&self, name: impl Into) -> Option> { self.get(name)?.to_url() } - - #[inline] - pub fn first(&self) -> Option<&Data> { self.get(0) } - - #[inline] - pub fn first_str(&self) -> Option<&str> { self.str(0) } - - #[inline] - pub fn second(&self) -> Option<&Data> { self.get(1) } - - #[inline] - pub fn second_str(&self) -> Option<&str> { self.str(1) } + pub fn seq<'a, T>(&'a self) -> Vec + where + T: TryFrom<&'a Data>, + { + let mut seq = Vec::with_capacity(self.len()); + for i in 0..self.len() { + if let Ok(data) = self.get::<&Data>(i) + && let Ok(v) = data.try_into() + { + seq.push(v); + } else { + break; + } + } + seq + } // --- Take - #[inline] - pub fn take(&mut self, name: impl Into) -> Option { - self.args.remove(&name.into()) + pub fn take<'a, T>(&mut self, name: impl Into) -> Result + where + T: TryFrom, + T::Error: Into, + { + let name = name.into(); + match self.args.remove(&name) { + Some(data) => data.try_into().map_err(Into::into), + None => bail!("argument not found: {:?}", name), + } } - #[inline] - pub fn take_str(&mut self, name: impl Into) -> Option { - if let Some(Data::String(s)) = self.take(name) { Some(s) } else { None } + pub fn take_first<'a, T>(&mut self) -> Result + where + T: TryFrom, + T::Error: Into, + { + self.take(0) } - #[inline] - pub fn take_first(&mut self) -> Option { self.take(0) } - - #[inline] - pub fn take_first_str(&mut self) -> Option { - if let Some(Data::String(s)) = self.take_first() { Some(s) } else { None } + pub fn take_seq(&mut self) -> Vec + where + T: TryFrom, + { + let mut seq = Vec::with_capacity(self.len()); + for i in 0..self.len() { + if let Ok(data) = self.take::(i) + && let Ok(v) = data.try_into() + { + seq.push(v); + } else { + break; + } + } + seq } - #[inline] - pub fn take_first_url(&mut self) -> Option> { self.take_first()?.into_url() } - - #[inline] pub fn take_any(&mut self, name: impl Into) -> Option { self.args.remove(&name.into())?.into_any() } - #[inline] pub fn take_any2(&mut self, name: impl Into) -> Option> { self.args.remove(&name.into()).map(Data::into_any2) } @@ -192,7 +218,7 @@ impl Display for Cmd { } } DataKey::String(k) => { - if v.as_bool().is_some_and(|b| b) { + if v.try_into().is_ok_and(|b| b) { write!(f, " --{k}")?; } else if let Some(s) = v.as_str() { write!(f, " --{k}={s}")?; diff --git a/yazi-shared/src/event/cow.rs b/yazi-shared/src/event/cow.rs index 1fb1775c..309b5782 100644 --- a/yazi-shared/src/event/cow.rs +++ b/yazi-shared/src/event/cow.rs @@ -1,9 +1,9 @@ -use std::{borrow::Cow, ops::Deref}; +use std::ops::Deref; use anyhow::Result; -use super::{Cmd, Data, DataKey}; -use crate::{SStr, url::UrlCow}; +use super::Cmd; +use crate::data::{Data, DataKey}; #[derive(Debug)] pub enum CmdCow { @@ -31,46 +31,42 @@ impl Deref for CmdCow { } impl CmdCow { - #[inline] - pub fn try_take(&mut self, name: impl Into) -> Option { + pub fn take<'a, T>(&mut self, name: impl Into) -> Result + where + T: TryFrom + TryFrom<&'a Data>, + >::Error: Into, + >::Error: Into, + { match self { Self::Owned(c) => c.take(name), - Self::Borrowed(_) => None, + Self::Borrowed(c) => c.get(name), } } - #[inline] - pub fn take_str(&mut self, name: impl Into) -> Option { + pub fn take_first<'a, T>(&mut self) -> Result + where + T: TryFrom + TryFrom<&'a Data>, + >::Error: Into, + >::Error: Into, + { match self { - Self::Owned(c) => c.take_str(name), - Self::Borrowed(c) => c.str(name).map(Cow::Borrowed), + Self::Owned(c) => c.take_first(), + Self::Borrowed(c) => c.first(), } } - #[inline] - pub fn take_url(&mut self, name: impl Into) -> Option> { + pub fn take_seq<'a, T>(&mut self) -> Vec + where + T: TryFrom + TryFrom<&'a Data>, + >::Error: Into, + >::Error: Into, + { match self { - Self::Owned(c) => c.take(name).and_then(Data::into_url), - Self::Borrowed(c) => c.url(name), + Self::Owned(c) => c.take_seq(), + Self::Borrowed(c) => c.seq(), } } - #[inline] - pub fn take_first_str(&mut self) -> Option { - match self { - Self::Owned(c) => c.take_first_str(), - Self::Borrowed(c) => c.first_str().map(Cow::Borrowed), - } - } - - pub fn take_first_url(&mut self) -> Option> { - match self { - Self::Owned(c) => c.take_first_url(), - Self::Borrowed(c) => c.first().and_then(Data::to_url), - } - } - - #[inline] pub fn take_any(&mut self, name: impl Into) -> Option { match self { Self::Owned(c) => c.take_any(name), @@ -78,7 +74,6 @@ impl CmdCow { } } - #[inline] pub fn take_any2(&mut self, name: impl Into) -> Option> { match self { Self::Owned(c) => c.take_any2(name), diff --git a/yazi-shared/src/event/data.rs b/yazi-shared/src/event/data.rs deleted file mode 100644 index 17d1300b..00000000 --- a/yazi-shared/src/event/data.rs +++ /dev/null @@ -1,276 +0,0 @@ -use std::{any::Any, borrow::Cow}; - -use anyhow::{Result, bail}; -use hashbrown::HashMap; -use ordered_float::OrderedFloat; -use serde::{Deserialize, Serialize, de}; - -use crate::{Id, SStr, url::{UrlBuf, UrlCow, UrnBuf}}; - -// --- Data -#[derive(Debug, Deserialize, Serialize)] -#[serde(untagged)] -pub enum Data { - Nil, - Boolean(bool), - Integer(i64), - Number(f64), - String(SStr), - List(Vec), - Dict(HashMap), - Id(Id), - #[serde(skip_deserializing)] - Url(UrlBuf), - #[serde(skip_deserializing)] - Urn(UrnBuf), - #[serde(skip)] - Bytes(Vec), - #[serde(skip)] - Any(Box), -} - -impl Data { - #[inline] - pub fn as_bool(&self) -> Option { - match self { - Self::Boolean(b) => Some(*b), - Self::String(s) if s == "no" => Some(false), - Self::String(s) if s == "yes" => Some(true), - _ => None, - } - } - - #[inline] - pub fn as_str(&self) -> Option<&str> { - match self { - Self::String(s) => Some(s), - _ => None, - } - } - - #[inline] - pub fn into_string(self) -> Option { - match self { - Self::String(s) => Some(s), - _ => None, - } - } - - #[inline] - pub fn into_dict(self) -> Option> { - match self { - Self::Dict(d) => Some(d), - _ => None, - } - } - - #[inline] - pub fn into_url(self) -> Option> { - match self { - Self::String(s) => s.try_into().ok(), - Self::Url(u) => Some(u.into()), - Self::Bytes(b) => b.try_into().ok(), - _ => None, - } - } - - #[inline] - pub fn into_any(self) -> Option { - match self { - Self::Any(b) => b.downcast::().ok().map(|b| *b), - _ => None, - } - } - - // FIXME: find a better name - #[inline] - pub fn into_any2(self) -> Result { - if let Self::Any(b) = self - && let Ok(t) = b.downcast::() - { - Ok(*t) - } else { - bail!("Failed to downcast Data into {}", std::any::type_name::()) - } - } - - #[inline] - pub fn to_url(&self) -> Option> { - match self { - Self::String(s) => s.as_ref().try_into().ok(), - Self::Url(u) => Some(u.into()), - Self::Bytes(b) => b.as_slice().try_into().ok(), - _ => None, - } - } -} - -impl From<()> for Data { - fn from(_: ()) -> Self { Self::Nil } -} - -impl From for Data { - fn from(value: bool) -> Self { Self::Boolean(value) } -} - -impl From for Data { - fn from(value: i32) -> Self { Self::Integer(value as i64) } -} - -impl From for Data { - fn from(value: i64) -> Self { Self::Integer(value) } -} - -impl From for Data { - fn from(value: f64) -> Self { Self::Number(value) } -} - -impl From for Data { - fn from(value: usize) -> Self { Self::Id(value.into()) } -} - -impl From for Data { - fn from(value: String) -> Self { Self::String(Cow::Owned(value)) } -} - -impl From for Data { - fn from(value: SStr) -> Self { Self::String(value) } -} - -impl From for Data { - fn from(value: Id) -> Self { Self::Id(value) } -} - -impl From<&UrlBuf> for Data { - fn from(value: &UrlBuf) -> Self { Self::Url(value.clone()) } -} - -impl From<&str> for Data { - fn from(value: &str) -> Self { Self::String(Cow::Owned(value.to_owned())) } -} - -impl PartialEq for Data { - fn eq(&self, other: &bool) -> bool { self.as_bool() == Some(*other) } -} - -// --- Key -#[derive(Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -#[serde(untagged)] -pub enum DataKey { - Nil, - Boolean(bool), - #[serde(deserialize_with = "Self::deserialize_integer")] - Integer(i64), - Number(OrderedFloat), - String(SStr), - Id(Id), - #[serde(skip_deserializing)] - Url(UrlBuf), - #[serde(skip_deserializing)] - Urn(UrnBuf), - #[serde(skip)] - Bytes(Vec), -} - -impl DataKey { - #[inline] - pub fn is_integer(&self) -> bool { matches!(self, Self::Integer(_)) } - - #[inline] - pub fn as_str(&self) -> Option<&str> { - match self { - Self::String(s) => Some(s), - _ => None, - } - } - - #[inline] - pub fn into_url(self) -> Option> { - match self { - Self::String(s) => s.try_into().ok(), - Self::Url(u) => Some(u.into()), - Self::Bytes(b) => b.try_into().ok(), - _ => None, - } - } - - fn deserialize_integer<'de, D>(deserializer: D) -> Result - where - D: de::Deserializer<'de>, - { - struct Visitor; - - impl de::Visitor<'_> for Visitor { - type Value = i64; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("an integer or a string of an integer") - } - - fn visit_i64(self, value: i64) -> Result { Ok(value) } - - fn visit_str(self, value: &str) -> Result - where - E: de::Error, - { - value.parse().map_err(de::Error::custom) - } - } - - deserializer.deserialize_any(Visitor) - } -} - -impl From for DataKey { - fn from(value: usize) -> Self { Self::Integer(value as i64) } -} - -impl From<&'static str> for DataKey { - fn from(value: &'static str) -> Self { Self::String(Cow::Borrowed(value)) } -} - -impl From for DataKey { - fn from(value: String) -> Self { Self::String(Cow::Owned(value)) } -} - -// --- Macros -macro_rules! impl_as_integer { - ($t:ty, $name:ident) => { - impl Data { - #[inline] - pub fn $name(&self) -> Option<$t> { - match self { - Self::Integer(i) => <$t>::try_from(*i).ok(), - Self::String(s) => s.parse().ok(), - Self::Id(i) => <$t>::try_from(i.get()).ok(), - _ => None, - } - } - } - }; -} - -macro_rules! impl_as_number { - ($t:ty, $name:ident) => { - impl Data { - #[inline] - pub fn $name(&self) -> Option<$t> { - match self { - Self::Integer(i) if *i == (*i as $t as _) => Some(*i as $t), - Self::Number(n) => <$t>::try_from(*n).ok(), - Self::String(s) => s.parse().ok(), - Self::Id(i) if i.0 == (i.0 as $t as _) => Some(i.0 as $t), - _ => None, - } - } - } - }; -} - -impl_as_integer!(usize, as_usize); -impl_as_integer!(isize, as_isize); -impl_as_integer!(i16, as_i16); -impl_as_integer!(i32, as_i32); -impl_as_integer!(crate::Id, as_id); - -impl_as_number!(f64, as_f64); diff --git a/yazi-shared/src/event/mod.rs b/yazi-shared/src/event/mod.rs index 1399e145..febfd0a4 100644 --- a/yazi-shared/src/event/mod.rs +++ b/yazi-shared/src/event/mod.rs @@ -1,5 +1,5 @@ #![allow(clippy::module_inception)] -yazi_macro::mod_flat!(cmd cow data event); +yazi_macro::mod_flat!(cmd cow event); pub static NEED_RENDER: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); diff --git a/yazi-shared/src/lib.rs b/yazi-shared/src/lib.rs index 59b347e7..cd17b74c 100644 --- a/yazi-shared/src/lib.rs +++ b/yazi-shared/src/lib.rs @@ -1,6 +1,6 @@ #![allow(clippy::option_map_unit_fn)] -yazi_macro::mod_pub!(errors event loc pool shell translit url scheme); +yazi_macro::mod_pub!(data errors event loc pool scheme shell translit url); yazi_macro::mod_flat!(alias bytes chars condition debounce either env id layer natsort os osstr rand ro_cell source string sync_cell terminal tests throttle time utf8); diff --git a/yazi-shared/src/scheme/cow.rs b/yazi-shared/src/scheme/cow.rs index e8798934..217410bc 100644 --- a/yazi-shared/src/scheme/cow.rs +++ b/yazi-shared/src/scheme/cow.rs @@ -5,7 +5,7 @@ use percent_encoding::percent_decode; use crate::{BytesExt, pool::InternStr, scheme::{Scheme, SchemeRef}}; -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum SchemeCow<'a> { Borrowed(SchemeRef<'a>), Owned(Scheme), diff --git a/yazi-shared/src/url/cow.rs b/yazi-shared/src/url/cow.rs index b09154fe..30e5a992 100644 --- a/yazi-shared/src/url/cow.rs +++ b/yazi-shared/src/url/cow.rs @@ -1,11 +1,11 @@ -use std::{borrow::Cow, path::{Path, PathBuf}}; +use std::{borrow::Cow, ffi::OsStr, path::{Path, PathBuf}}; use anyhow::Result; use percent_encoding::percent_decode; use crate::{IntoOsStr, loc::{Loc, LocBuf}, scheme::{SchemeCow, SchemeRef}, url::{Components, Url, UrlBuf, Urn}}; -#[derive(Debug)] +#[derive(Clone, Debug)] pub enum UrlCow<'a> { Borrowed { loc: Loc<'a>, scheme: SchemeCow<'a> }, Owned { loc: LocBuf, scheme: SchemeCow<'a> }, @@ -25,6 +25,10 @@ impl<'a> From<&'a UrlBuf> for UrlCow<'a> { } } +impl<'a> From<&'a UrlCow<'a>> for UrlCow<'a> { + fn from(value: &'a UrlCow<'a>) -> Self { value.as_url().into() } +} + impl From for UrlCow<'_> { fn from(value: UrlBuf) -> Self { Self::Owned { loc: value.loc, scheme: value.scheme.into() } } } @@ -137,6 +141,18 @@ impl<'a> UrlCow<'a> { } } + // FIXME: remove + #[inline] + pub fn into_os_str2(self) -> Cow<'a, OsStr> { + match self { + UrlCow::Borrowed { loc, .. } => loc.as_path().as_os_str().into(), + UrlCow::Owned { loc, .. } => loc.into_path().into_os_string().into(), + } + } + + #[inline] + pub fn to_owned(&self) -> UrlBuf { self.as_url().into() } + #[inline] pub fn parent(&self) -> Option> { self.as_url().parent() } diff --git a/yazi-shared/src/url/mod.rs b/yazi-shared/src/url/mod.rs index 212e282c..53dbec67 100644 --- a/yazi-shared/src/url/mod.rs +++ b/yazi-shared/src/url/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(buf component cov cow display encode uri url urn); +yazi_macro::mod_flat!(buf component cov cow display encode traits uri url urn); diff --git a/yazi-shared/src/url/traits.rs b/yazi-shared/src/url/traits.rs new file mode 100644 index 00000000..d3f55b9c --- /dev/null +++ b/yazi-shared/src/url/traits.rs @@ -0,0 +1,20 @@ +use crate::url::{Url, UrlCow}; + +pub trait AsUrl { + fn as_url(&self) -> Url<'_>; +} + +impl AsUrl for Url<'_> { + #[inline] + fn as_url(&self) -> Url<'_> { *self } +} + +impl AsUrl for UrlCow<'_> { + #[inline] + fn as_url(&self) -> Url<'_> { self.as_url() } +} + +impl AsUrl for &UrlCow<'_> { + #[inline] + fn as_url(&self) -> Url<'_> { (*self).as_url() } +} diff --git a/yazi-vfs/src/fns.rs b/yazi-vfs/src/fns.rs index 6fc1d8ad..66e484ab 100644 --- a/yazi-vfs/src/fns.rs +++ b/yazi-vfs/src/fns.rs @@ -2,6 +2,7 @@ use std::{ffi::OsString, io}; use tokio::{select, sync::{mpsc, oneshot}}; use yazi_fs::cha::Cha; +use yazi_macro::ok_or_not_found; use yazi_shared::url::{Url, UrlBuf}; use crate::provider; @@ -42,9 +43,8 @@ async fn _unique_name(mut url: UrlBuf, append: bool) -> io::Result { s }); - let mut i = 1u64; let mut name = OsString::with_capacity(stem.len() + dot_ext.len() + 5); - loop { + for i in 1u64.. { name.clear(); name.push(&stem); @@ -57,11 +57,7 @@ async fn _unique_name(mut url: UrlBuf, append: bool) -> io::Result { } url.set_name(&name); - match provider::symlink_metadata(&url).await { - Ok(_) => i += 1, - Err(e) if e.kind() == io::ErrorKind::NotFound => break, - Err(e) => return Err(e), - } + ok_or_not_found!(provider::symlink_metadata(&url).await, break); } Ok(url) diff --git a/yazi-vfs/src/provider/sftp/sftp.rs b/yazi-vfs/src/provider/sftp/sftp.rs index a976e9ce..1dfd105a 100644 --- a/yazi-vfs/src/provider/sftp/sftp.rs +++ b/yazi-vfs/src/provider/sftp/sftp.rs @@ -254,7 +254,7 @@ impl Sftp { let session = if self.config.password.is_some() { self.connect_by_password(pref).await - } else if self.config.key_file.is_some() { + } else if !self.config.key_file.as_os_str().is_empty() { self.connect_by_key(pref).await } else { self.connect_by_agent(pref).await @@ -287,7 +287,8 @@ impl Sftp { self, pref: Arc, ) -> Result, russh::Error> { - let Some(key_file) = &self.config.key_file else { + let key_file = &self.config.key_file; + if key_file.as_os_str().is_empty() { return Err(russh::Error::InvalidConfig("Key file not provided".to_owned())); }; @@ -322,7 +323,8 @@ impl Sftp { self, pref: Arc, ) -> Result, russh::Error> { - let Some(identity_agent) = &self.config.identity_agent else { + let identity_agent = &self.config.identity_agent; + if identity_agent.as_os_str().is_empty() { return Err(russh::Error::InvalidConfig("Identity agent not provided".to_owned())); }; diff --git a/yazi-widgets/src/input/commands/backspace.rs b/yazi-widgets/src/input/commands/backspace.rs index d93e304f..3af0b9be 100644 --- a/yazi-widgets/src/input/commands/backspace.rs +++ b/yazi-widgets/src/input/commands/backspace.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::input::BackspaceOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::Input; diff --git a/yazi-widgets/src/input/commands/backward.rs b/yazi-widgets/src/input/commands/backward.rs index 3b7cd3b1..4a93b560 100644 --- a/yazi-widgets/src/input/commands/backward.rs +++ b/yazi-widgets/src/input/commands/backward.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::input::BackwardOpt; -use yazi_shared::{CharKind, event::Data}; +use yazi_shared::{CharKind, data::Data}; use crate::input::Input; diff --git a/yazi-widgets/src/input/commands/commands.rs b/yazi-widgets/src/input/commands/commands.rs index 881e4d5f..ba6ed220 100644 --- a/yazi-widgets/src/input/commands/commands.rs +++ b/yazi-widgets/src/input/commands/commands.rs @@ -1,6 +1,6 @@ use anyhow::Result; use yazi_macro::{act, succ}; -use yazi_shared::event::{CmdCow, Data}; +use yazi_shared::{data::Data, event::CmdCow}; use crate::input::{Input, InputMode}; diff --git a/yazi-widgets/src/input/commands/complete.rs b/yazi-widgets/src/input/commands/complete.rs index 8c85e087..c31a2df0 100644 --- a/yazi-widgets/src/input/commands/complete.rs +++ b/yazi-widgets/src/input/commands/complete.rs @@ -3,7 +3,7 @@ use std::path::MAIN_SEPARATOR_STR; use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::input::CompleteOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::Input; diff --git a/yazi-widgets/src/input/commands/delete.rs b/yazi-widgets/src/input/commands/delete.rs index 6eca69a3..e1ce6745 100644 --- a/yazi-widgets/src/input/commands/delete.rs +++ b/yazi-widgets/src/input/commands/delete.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::input::DeleteOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::{Input, op::InputOp}; diff --git a/yazi-widgets/src/input/commands/escape.rs b/yazi-widgets/src/input/commands/escape.rs index 4e384c12..b213487b 100644 --- a/yazi-widgets/src/input/commands/escape.rs +++ b/yazi-widgets/src/input/commands/escape.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::{Input, InputMode, op::InputOp}; diff --git a/yazi-widgets/src/input/commands/forward.rs b/yazi-widgets/src/input/commands/forward.rs index 2e5f5b83..a4e19394 100644 --- a/yazi-widgets/src/input/commands/forward.rs +++ b/yazi-widgets/src/input/commands/forward.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::act; use yazi_parser::input::ForwardOpt; -use yazi_shared::{CharKind, event::Data}; +use yazi_shared::{CharKind, data::Data}; use crate::input::{Input, op::InputOp}; diff --git a/yazi-widgets/src/input/commands/insert.rs b/yazi-widgets/src/input/commands/insert.rs index 18b7d6d1..9bc024b0 100644 --- a/yazi-widgets/src/input/commands/insert.rs +++ b/yazi-widgets/src/input/commands/insert.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::input::InsertOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::{Input, InputMode, op::InputOp}; diff --git a/yazi-widgets/src/input/commands/kill.rs b/yazi-widgets/src/input/commands/kill.rs index febceff4..5f7e434b 100644 --- a/yazi-widgets/src/input/commands/kill.rs +++ b/yazi-widgets/src/input/commands/kill.rs @@ -3,7 +3,7 @@ use std::ops::RangeBounds; use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::input::KillOpt; -use yazi_shared::{CharKind, event::Data}; +use yazi_shared::{CharKind, data::Data}; use crate::input::Input; diff --git a/yazi-widgets/src/input/commands/move.rs b/yazi-widgets/src/input/commands/move.rs index 38ee0990..4cebbbef 100644 --- a/yazi-widgets/src/input/commands/move.rs +++ b/yazi-widgets/src/input/commands/move.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::input::MoveOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::{Input, op::InputOp, snap::InputSnap}; diff --git a/yazi-widgets/src/input/commands/paste.rs b/yazi-widgets/src/input/commands/paste.rs index 4cd0c072..5f795ae8 100644 --- a/yazi-widgets/src/input/commands/paste.rs +++ b/yazi-widgets/src/input/commands/paste.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::input::PasteOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::{CLIPBOARD, input::{Input, op::InputOp}}; diff --git a/yazi-widgets/src/input/commands/redo.rs b/yazi-widgets/src/input/commands/redo.rs index 7648e58f..a4511e0a 100644 --- a/yazi-widgets/src/input/commands/redo.rs +++ b/yazi-widgets/src/input/commands/redo.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::Input; diff --git a/yazi-widgets/src/input/commands/replace.rs b/yazi-widgets/src/input/commands/replace.rs index c26b5021..2acc8879 100644 --- a/yazi-widgets/src/input/commands/replace.rs +++ b/yazi-widgets/src/input/commands/replace.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::{event::Data, replace_cow}; +use yazi_shared::{data::Data, replace_cow}; use crate::input::{Input, InputMode, op::InputOp}; diff --git a/yazi-widgets/src/input/commands/type.rs b/yazi-widgets/src/input/commands/type.rs index ccd6e7eb..2685a750 100644 --- a/yazi-widgets/src/input/commands/type.rs +++ b/yazi-widgets/src/input/commands/type.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_config::keymap::Key; use yazi_macro::{act, render, succ}; -use yazi_shared::{event::Data, replace_cow}; +use yazi_shared::{data::Data, replace_cow}; use crate::input::{Input, InputMode}; diff --git a/yazi-widgets/src/input/commands/undo.rs b/yazi-widgets/src/input/commands/undo.rs index 2144403a..1f0c1a6f 100644 --- a/yazi-widgets/src/input/commands/undo.rs +++ b/yazi-widgets/src/input/commands/undo.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::{Input, InputMode}; diff --git a/yazi-widgets/src/input/commands/visual.rs b/yazi-widgets/src/input/commands/visual.rs index 0ed8a271..fcfa3485 100644 --- a/yazi-widgets/src/input/commands/visual.rs +++ b/yazi-widgets/src/input/commands/visual.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::{Input, InputMode, op::InputOp}; diff --git a/yazi-widgets/src/input/commands/yank.rs b/yazi-widgets/src/input/commands/yank.rs index 36dade19..57759f7e 100644 --- a/yazi-widgets/src/input/commands/yank.rs +++ b/yazi-widgets/src/input/commands/yank.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, render, succ}; use yazi_parser::VoidOpt; -use yazi_shared::event::Data; +use yazi_shared::data::Data; use crate::input::{Input, op::InputOp};