mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-23 07:41:03 +00:00
refactor: move Lua bindings down into each subcrates (#4049)
This commit is contained in:
parent
f1e93d7f52
commit
446a5721bf
439 changed files with 3465 additions and 4058 deletions
420
Cargo.lock
generated
420
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -50,6 +50,7 @@ foldhash = "0.2.0"
|
|||
futures = "0.3.32"
|
||||
globset = "0.4.18"
|
||||
hashbrown = { version = "0.17.1", features = [ "serde" ] }
|
||||
image = { version = "0.25.10", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] }
|
||||
indexmap = { version = "2.14.0", features = [ "serde" ] }
|
||||
inventory = "0.3.24"
|
||||
libc = "0.2.186"
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ impl Actor for Dnd {
|
|||
const NAME: &str = "dnd";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let event = yazi_binding::DndEvent::from(form.event);
|
||||
|
||||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let area = yazi_binding::elements::Rect::from(size);
|
||||
|
||||
|
|
@ -27,10 +25,10 @@ impl Actor for Dnd {
|
|||
runtime_scope!(LUA, "root", {
|
||||
let root = LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)?;
|
||||
|
||||
if event.is_drag() {
|
||||
root.call_method::<()>("drag", event)?;
|
||||
if form.event.is_drag() {
|
||||
root.call_method::<()>("drag", form.event)?;
|
||||
} else {
|
||||
root.call_method::<()>("drop", event)?;
|
||||
root.call_method::<()>("drop", form.event)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use anyhow::Result;
|
||||
use yazi_binding::{Sendable, runtime_scope};
|
||||
use yazi_binding::runtime_scope;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::app::LuaForm;
|
||||
use yazi_plugin::LUA;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_shared::data::{Data, Sendable};
|
||||
|
||||
use crate::{Actor, Ctx, lives::Lives};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ impl Actor for Mouse {
|
|||
const NAME: &str = "mouse";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let event = yazi_binding::MouseEvent::from(form.event);
|
||||
|
||||
let Some(size) = cx.term.as_ref().and_then(|t| t.size().ok()) else { succ!() };
|
||||
let area = yazi_binding::elements::Rect::from(size);
|
||||
|
||||
|
|
@ -28,18 +26,18 @@ impl Actor for Mouse {
|
|||
runtime_scope!(LUA, "root", {
|
||||
let root = LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)?;
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => root.call_method("click", (event, false))?,
|
||||
MouseEventKind::Up(_) => root.call_method("click", (event, true))?,
|
||||
match form.event.kind {
|
||||
MouseEventKind::Down(_) => root.call_method("click", (form.event, false))?,
|
||||
MouseEventKind::Up(_) => root.call_method("click", (form.event, true))?,
|
||||
|
||||
MouseEventKind::ScrollDown => root.call_method("scroll", (event, 1))?,
|
||||
MouseEventKind::ScrollUp => root.call_method("scroll", (event, -1))?,
|
||||
MouseEventKind::ScrollDown => root.call_method("scroll", (form.event, 1))?,
|
||||
MouseEventKind::ScrollUp => root.call_method("scroll", (form.event, -1))?,
|
||||
|
||||
MouseEventKind::ScrollRight => root.call_method("touch", (event, 1))?,
|
||||
MouseEventKind::ScrollLeft => root.call_method("touch", (event, -1))?,
|
||||
MouseEventKind::ScrollRight => root.call_method("touch", (form.event, 1))?,
|
||||
MouseEventKind::ScrollLeft => root.call_method("touch", (form.event, -1))?,
|
||||
|
||||
MouseEventKind::Moved => root.call_method("move", event)?,
|
||||
MouseEventKind::Drag(_) => root.call_method("drag", event)?,
|
||||
MouseEventKind::Moved => root.call_method("move", form.event)?,
|
||||
MouseEventKind::Drag(_) => root.call_method("drag", form.event)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ use yazi_actor::Ctx;
|
|||
use yazi_macro::{succ, writef};
|
||||
use yazi_parser::{app::TitleForm, spark::SparkKind};
|
||||
use yazi_shared::{Source, data::Data};
|
||||
use yazi_term::sequence::SetTitle;
|
||||
use yazi_tty::TTY;
|
||||
use yazi_tty::{TTY, sequence::SetTitle};
|
||||
use yazi_tui::RatermState;
|
||||
|
||||
use crate::Actor;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::ops::{Deref, DerefMut};
|
|||
|
||||
use anyhow::{Result, anyhow};
|
||||
use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}};
|
||||
use yazi_fs::File;
|
||||
use yazi_shared::{Id, Source, event::Action, url::UrlBuf};
|
||||
use yazi_fs::file::File;
|
||||
use yazi_shared::{Source, event::Action, id::Id, url::UrlBuf};
|
||||
use yazi_tui::Raterm;
|
||||
|
||||
pub struct Ctx<'a> {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,31 @@
|
|||
use anyhow::Result;
|
||||
use ratatui::widgets::Padding;
|
||||
use yazi_config::{THEME, YAZI};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::input::ShowForm;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_widgets::input::InputOpt;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct Show;
|
||||
|
||||
impl Actor for Show {
|
||||
type Form = InputOpt;
|
||||
type Form = ShowForm;
|
||||
|
||||
const NAME: &str = "show";
|
||||
|
||||
fn act(cx: &mut Ctx, mut form: Self::Form) -> Result<Data> {
|
||||
fn act(cx: &mut Ctx, Self::Form { mut opt }: Self::Form) -> Result<Data> {
|
||||
act!(input:close, cx)?;
|
||||
|
||||
let input = &mut cx.input;
|
||||
input.main_visible = true;
|
||||
input.main_title = form.cfg.title.clone();
|
||||
input.main_position = form.cfg.position;
|
||||
input.main_title = opt.title.clone();
|
||||
input.main_position = opt.position;
|
||||
|
||||
form.cfg.position = form.cfg.position.padding(Padding::uniform(1));
|
||||
input.main = yazi_widgets::input::Input::new(form)?;
|
||||
opt.styles = (&THEME.input).into();
|
||||
opt.blinking = YAZI.input.cursor_blink;
|
||||
opt.position = opt.position.padding(Padding::uniform(1));
|
||||
input.main = yazi_widgets::input::Input::new(opt)?;
|
||||
|
||||
succ!(render!());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,9 +63,7 @@ impl UserData for Core {
|
|||
b"yanked" => reuse!(yanked, super::Yanked::make(&me.mgr.yanked)),
|
||||
b"input" => reuse!(input, super::Input::make(&me.input)),
|
||||
b"which" => reuse!(which, super::Which::make(&me.which)),
|
||||
b"layer" => {
|
||||
reuse!(layer, Ok::<_, mlua::Error>(yazi_binding::Layer::from(me.layer())))
|
||||
}
|
||||
b"layer" => reuse!(layer, Ok::<_, mlua::Error>(me.layer())),
|
||||
_ => Value::Nil,
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{ops::Deref, ptr};
|
||||
|
||||
use mlua::{AnyUserData, IntoLua, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_binding::{Range, Style};
|
||||
use yazi_binding::{Range, style::Style};
|
||||
use yazi_config::THEME;
|
||||
use yazi_shared::{path::AsPath, url::UrlLike};
|
||||
|
||||
|
|
@ -15,13 +15,13 @@ pub(super) struct File {
|
|||
}
|
||||
|
||||
impl Deref for File {
|
||||
type Target = yazi_fs::File;
|
||||
type Target = yazi_fs::file::File;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.folder.files[self.idx] }
|
||||
}
|
||||
|
||||
impl AsRef<yazi_fs::File> for File {
|
||||
fn as_ref(&self) -> &yazi_fs::File { self }
|
||||
impl AsRef<yazi_fs::file::File> for File {
|
||||
fn as_ref(&self) -> &yazi_fs::file::File { self }
|
||||
}
|
||||
|
||||
impl File {
|
||||
|
|
@ -49,7 +49,7 @@ impl File {
|
|||
impl UserData for File {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
yazi_binding::impl_file_fields!(fields);
|
||||
fields.add_cached_field("bare", |_, me| Ok(yazi_binding::File::new(&**me)));
|
||||
fields.add_cached_field("bare", |_, me| Ok(yazi_fs::file::File::from(&**me)));
|
||||
|
||||
fields.add_field_method_get("idx", |_, me| Ok(me.idx + 1));
|
||||
fields.add_field_method_get("is_hovered", |_, me| Ok(me.is_hovered()));
|
||||
|
|
@ -63,9 +63,8 @@ impl UserData for File {
|
|||
yazi_binding::impl_file_methods!(methods);
|
||||
|
||||
methods.add_method("icon", |_, me, ()| {
|
||||
use yazi_binding::Icon;
|
||||
// TODO: use a cache
|
||||
Ok(yazi_config::THEME.icon.matches(me, me.is_hovered()).map(Icon::from))
|
||||
Ok(yazi_config::THEME.icon.matches(me, me.is_hovered()))
|
||||
});
|
||||
methods.add_method("size", |_, me, ()| {
|
||||
Ok(if me.is_dir() { me.folder.files.sizes.get(&me.urn()).copied() } else { Some(me.len) })
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::ops::{Deref, Range};
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields};
|
||||
use yazi_binding::{FolderStage, Url};
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
|
|
@ -39,9 +38,9 @@ impl Folder {
|
|||
|
||||
impl UserData for Folder {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("cwd", |_, me| Ok(Url::new(&me.url)));
|
||||
fields.add_cached_field("cwd", |_, me| Ok(me.url.clone()));
|
||||
fields.add_static_field("files", |_, me| Files::make(0..me.files.len(), me, &me.tab));
|
||||
fields.add_cached_field("stage", |_, me| Ok(FolderStage::new(me.stage.clone())));
|
||||
fields.add_cached_field("stage", |_, me| Ok(me.stage.clone()));
|
||||
fields.add_static_field("window", |_, me| Files::make(me.window.clone(), me, &me.tab));
|
||||
|
||||
fields.add_field_method_get("offset", |_, me| Ok(me.offset));
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ use super::{Core, PtrCell};
|
|||
use crate::lives::MutCell;
|
||||
|
||||
pub(super) static TO_DESTROY: MutCell<Vec<AnyUserData>> = MutCell::new(Vec::new());
|
||||
pub(super) static FILE_CACHE: MutCell<MaybeUninit<HashMap<PtrCell<yazi_fs::File>, AnyUserData>>> =
|
||||
MutCell::new(MaybeUninit::uninit());
|
||||
pub(super) static FILE_CACHE: MutCell<
|
||||
MaybeUninit<HashMap<PtrCell<yazi_fs::file::File>, AnyUserData>>,
|
||||
> = MutCell::new(MaybeUninit::uninit());
|
||||
|
||||
pub struct Lives;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use mlua::AnyUserData;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
|
||||
use super::Lives;
|
||||
use crate::lives::PtrCell;
|
||||
|
|
@ -11,7 +12,7 @@ impl Selected {
|
|||
let inner = PtrCell::from(inner);
|
||||
|
||||
Lives::scoped_userdata(yazi_binding::Iter::new(
|
||||
inner.as_static().values().map(yazi_binding::Url::new),
|
||||
inner.as_static().values().map(UrlBuf::from),
|
||||
Some(inner.len()),
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{borrow::Cow, ops::Deref};
|
||||
|
||||
use mlua::{AnyUserData, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_binding::{Id, UrlRef};
|
||||
use yazi_shared::url::UrlRef;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use super::{Finder, Folder, Lives, Mode, Preference, Preview, PtrCell, Selected};
|
||||
|
|
@ -24,7 +24,7 @@ impl Tab {
|
|||
|
||||
impl UserData for Tab {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
fields.add_field_method_get("id", |_, me| Ok(me.id));
|
||||
fields.add_cached_field("name", |lua, me| match me.name() {
|
||||
Cow::Borrowed(s) => lua.create_string(s),
|
||||
Cow::Owned(s) => lua.create_external_string(s),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields};
|
||||
use yazi_binding::SER_OPT;
|
||||
use yazi_scheduler::Progress;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
use yazi_shim::mlua::{SER_OPT, UserDataFieldsExt};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields};
|
||||
use yazi_binding::SER_OPT;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
use yazi_shim::mlua::{SER_OPT, UserDataFieldsExt};
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
use crate::lives::{Behavior, TaskSnap};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ impl UserData for Which {
|
|||
fields.add_cached_field("tx", |_, me| Ok(me.tx.clone().map(yazi_binding::MpscUnboundedTx)));
|
||||
fields.add_field_method_get("times", |_, me| Ok(me.inner.times));
|
||||
fields.add_cached_field("cands", |lua, me| {
|
||||
lua.create_sequence_from(me.inner.cands.iter().map(yazi_binding::keymap::Chord::from))
|
||||
lua.create_sequence_from(me.inner.cands.iter().cloned())
|
||||
});
|
||||
|
||||
fields.add_field_method_get("active", |_, me| Ok(me.inner.active));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, MetaMethod, MultiValue, ObjectLike, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_binding::{Iter, get_metatable};
|
||||
use yazi_binding::Iter;
|
||||
use yazi_shared::url::UrlBuf;
|
||||
use yazi_shim::mlua::get_metatable;
|
||||
|
||||
use super::{Lives, PtrCell};
|
||||
|
||||
|
|
@ -23,7 +25,7 @@ impl Yanked {
|
|||
Lives::scoped_userdata(Self {
|
||||
inner,
|
||||
iter: Lives::scoped_userdata(Iter::new(
|
||||
inner.as_static().iter().map(yazi_binding::Url::new),
|
||||
inner.as_static().iter().map(UrlBuf::from),
|
||||
Some(inner.len()),
|
||||
))?,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
use std::{fmt::{self, Display}, io::{self, Read, Write}, path::{MAIN_SEPARATOR, Path}, sync::Arc};
|
||||
use std::{fmt::{self, Display}, io::{self, Read, Write}, path::{MAIN_SEPARATOR, Path}};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use scopeguard::defer;
|
||||
use yazi_binding::Permit;
|
||||
use yazi_config::{YAZI, opener::OpenerRule};
|
||||
use yazi_fs::{File, FilesOp, Splatter, provider::{Provider, local::Local}};
|
||||
use yazi_config::{YAZI, opener::OpenerRuleArc};
|
||||
use yazi_fs::{FilesOp, Splatter, file::File, provider::{Provider, local::Local}};
|
||||
use yazi_macro::{succ, writef};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_proxy::TasksProxy;
|
||||
use yazi_scheduler::{AppProxy, NotifyProxy};
|
||||
use yazi_shared::{data::Data, strand::Strand, url::{AsUrl, UrlBuf, UrlCow, UrlLike}};
|
||||
use yazi_shim::path::CROSS_SEPARATOR;
|
||||
use yazi_term::{YIELD_TO_SUBPROCESS, sequence::EraseScreen};
|
||||
use yazi_tty::TTY;
|
||||
use yazi_term::YIELD_TO_SUBPROCESS;
|
||||
use yazi_tty::{TTY, sequence::EraseScreen};
|
||||
use yazi_vfs::{VfsFile, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ impl BulkCreate {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn opener() -> Option<Arc<OpenerRule>> {
|
||||
fn opener() -> Option<OpenerRuleArc> {
|
||||
YAZI
|
||||
.open
|
||||
.match_dummy(Path::new("bulk-create.txt"), "text/plain")
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
use std::{hash::Hash, io::{Read, Write}, ops::Deref, path::Path, sync::Arc};
|
||||
use std::{hash::Hash, io::{Read, Write}, ops::Deref, path::Path};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use hashbrown::HashMap;
|
||||
use scopeguard::defer;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use yazi_binding::Permit;
|
||||
use yazi_config::{YAZI, opener::OpenerRule};
|
||||
use yazi_config::{YAZI, opener::OpenerRuleArc};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp, Splatter, max_common_root, path::skip_url, provider::{FileBuilder, Provider, local::{Gate, Local}}};
|
||||
use yazi_fs::{FilesOp, Splatter, file::File, max_common_root, path::skip_url, provider::{FileBuilder, Provider, local::{Gate, Local}}};
|
||||
use yazi_macro::{err, succ, writef};
|
||||
use yazi_parser::VoidForm;
|
||||
use yazi_proxy::TasksProxy;
|
||||
use yazi_scheduler::{AppProxy, NotifyProxy};
|
||||
use yazi_shared::{data::Data, path::PathDyn, strand::{AsStrand, AsStrandJoin, Strand, StrandBuf, StrandLike}, url::{AsUrl, UrlBuf, UrlCow, UrlLike}};
|
||||
use yazi_term::{YIELD_TO_SUBPROCESS, sequence::EraseScreen};
|
||||
use yazi_tty::TTY;
|
||||
use yazi_term::YIELD_TO_SUBPROCESS;
|
||||
use yazi_tty::{TTY, sequence::EraseScreen};
|
||||
use yazi_vfs::{VfsFile, maybe_exists, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ impl BulkRename {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn opener() -> Option<Arc<OpenerRule>> {
|
||||
fn opener() -> Option<OpenerRuleArc> {
|
||||
YAZI
|
||||
.open
|
||||
.match_dummy(Path::new("bulk-rename.txt"), "text/plain")
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ use std::{mem, time::Duration};
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::CdSource;
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp, path::{clean_url, expand_url}};
|
||||
use yazi_fs::{FilesOp, file::File, path::{clean_url, expand_url}};
|
||||
use yazi_macro::{act, err, input, render, succ};
|
||||
use yazi_parser::mgr::CdForm;
|
||||
use yazi_proxy::{CmpProxy, MgrProxy};
|
||||
|
|
@ -63,7 +63,7 @@ impl Actor for Cd {
|
|||
|
||||
impl Cd {
|
||||
fn cd_interactive(cx: &mut Ctx) -> Result<Data> {
|
||||
let input = input!(cx, InputCfg::cd(cx.cwd().as_url()))?;
|
||||
let input = input!(cx, YAZI.input.cd(cx.cwd().as_url()))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(input), Duration::from_millis(50));
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use anyhow::{Result, bail};
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_fs::{File, FilesOp};
|
||||
use yazi_config::{YAZI, popup::ConfirmCfg};
|
||||
use yazi_fs::{FilesOp, file::File};
|
||||
use yazi_macro::{input, ok_or_not_found, succ};
|
||||
use yazi_parser::mgr::CreateForm;
|
||||
use yazi_proxy::{ConfirmProxy, MgrProxy};
|
||||
|
|
@ -20,7 +20,7 @@ impl Actor for Create {
|
|||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let cwd = cx.cwd().to_owned();
|
||||
let mut input = input!(cx, InputCfg::create(form.dir))?;
|
||||
let mut input = input!(cx, YAZI.input.create(form.dir))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let Some(InputEvent::Submit(name)) = input.recv().await else { return };
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use anyhow::Result;
|
|||
use futures::{StreamExt, stream::FuturesUnordered};
|
||||
use hashbrown::HashSet;
|
||||
use yazi_core::mgr::OpenOpt;
|
||||
use yazi_fs::{File, FsScheme, provider::{Provider, local::Local}};
|
||||
use yazi_fs::{FsScheme, file::File, provider::{Provider, local::Local}};
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::DownloadForm;
|
||||
use yazi_proxy::MgrProxy;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::FilterOpt;
|
||||
use yazi_macro::{input, succ};
|
||||
use yazi_parser::mgr::FilterForm;
|
||||
|
|
@ -21,7 +21,7 @@ impl Actor for Filter {
|
|||
const NAME: &str = "filter";
|
||||
|
||||
fn act(cx: &mut Ctx, Self::Form { opt }: Self::Form) -> Result<Data> {
|
||||
let input = input!(cx, InputCfg::filter())?;
|
||||
let input = input!(cx, YAZI.input.filter())?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(input), Duration::from_millis(50));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::FindDoOpt;
|
||||
use yazi_macro::{input, succ};
|
||||
use yazi_parser::mgr::FindForm;
|
||||
|
|
@ -21,7 +21,7 @@ impl Actor for Find {
|
|||
const NAME: &str = "find";
|
||||
|
||||
fn act(cx: &mut Ctx, form: Self::Form) -> Result<Data> {
|
||||
let input = input!(cx, InputCfg::find(form.prev))?;
|
||||
let input = input!(cx, YAZI.input.find(form.prev))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let rx = Debounce::new(UnboundedReceiverStream::new(input), Duration::from_millis(50));
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use futures::StreamExt;
|
|||
use hashbrown::HashSet;
|
||||
use yazi_boot::ARGS;
|
||||
use yazi_core::mgr::OpenDoOpt;
|
||||
use yazi_fs::File;
|
||||
use yazi_fs::file::File;
|
||||
use yazi_macro::{act, succ};
|
||||
use yazi_parser::mgr::OpenForm;
|
||||
use yazi_proxy::MgrProxy;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use anyhow::Result;
|
||||
use hashbrown::HashMap;
|
||||
use indexmap::IndexSet;
|
||||
use yazi_config::{YAZI, popup::PickCfg};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_fs::file::File;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::OpenDoForm;
|
||||
use yazi_proxy::{PickProxy, TasksProxy};
|
||||
|
|
@ -40,7 +41,7 @@ impl Actor for OpenDo {
|
|||
succ!();
|
||||
}
|
||||
|
||||
let pick = PickProxy::show(PickCfg::open(openers.iter().map(|o| o.desc()).collect()));
|
||||
let pick = PickProxy::show(YAZI.pick.open(openers.iter().map(|o| o.desc()).collect()));
|
||||
let urls: Vec<_> = [UrlCow::default()]
|
||||
.into_iter()
|
||||
.chain(targets.into_iter().map(|(file, _)| file.url.into()))
|
||||
|
|
@ -63,7 +64,7 @@ impl Actor for OpenDo {
|
|||
|
||||
impl OpenDo {
|
||||
// TODO: remove
|
||||
fn match_and_open(cx: &Ctx, cwd: UrlBuf, targets: Vec<(yazi_fs::File, &str)>) {
|
||||
fn match_and_open(cx: &Ctx, cwd: UrlBuf, targets: Vec<(File, &str)>) {
|
||||
let mut openers = HashMap::new();
|
||||
for (file, mime) in targets {
|
||||
if let Some(open) = YAZI.open.matches(&file, mime)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use anyhow::Result;
|
||||
use yazi_config::popup::{ConfirmCfg, InputCfg};
|
||||
use yazi_config::{YAZI, popup::ConfirmCfg};
|
||||
use yazi_dds::Pubsub;
|
||||
use yazi_fs::{File, FilesOp};
|
||||
use yazi_fs::{FilesOp, file::File};
|
||||
use yazi_macro::{act, err, input, ok_or_not_found, succ};
|
||||
use yazi_parser::mgr::RenameForm;
|
||||
use yazi_proxy::{ConfirmProxy, MgrProxy};
|
||||
use yazi_shared::{Id, data::Data, url::{UrlBuf, UrlLike}};
|
||||
use yazi_shared::{data::Data, id::Id, url::{UrlBuf, UrlLike}};
|
||||
use yazi_vfs::{VfsFile, maybe_exists, provider};
|
||||
use yazi_watcher::WATCHER;
|
||||
use yazi_widgets::input::InputEvent;
|
||||
|
|
@ -42,7 +42,7 @@ impl Actor for Rename {
|
|||
};
|
||||
|
||||
let (tab, old) = (cx.tab().id, hovered.url_owned());
|
||||
let mut input = input!(cx, InputCfg::rename().with_value(name).with_cursor(cursor))?;
|
||||
let mut input = input!(cx, YAZI.input.rename().with_value(name).with_cursor(cursor))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
let Some(InputEvent::Submit(name)) = input.recv().await else { return };
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use anyhow::Result;
|
||||
use yazi_fs::{File, FilesOp};
|
||||
use yazi_fs::{FilesOp, file::File};
|
||||
use yazi_macro::{act, render, succ};
|
||||
use yazi_parser::mgr::RevealForm;
|
||||
use yazi_shared::{data::Data, url::UrlLike};
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{borrow::Cow, time::Duration};
|
|||
use anyhow::Result;
|
||||
use tokio::pin;
|
||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_core::mgr::{CdSource, SearchVia};
|
||||
use yazi_fs::{FilesOp, cha::Cha};
|
||||
use yazi_macro::{act, input, succ};
|
||||
|
|
@ -28,7 +28,7 @@ impl Actor for Search {
|
|||
handle.abort();
|
||||
}
|
||||
|
||||
let mut input = input!(cx, InputCfg::search(opt.via.into()).with_value(&*opt.subject))?;
|
||||
let mut input = input!(cx, YAZI.input.search(opt.via.into()).with_value(&*opt.subject))?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Some(InputEvent::Submit(subject)) = input.recv().await {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_macro::{act, input, succ};
|
||||
use yazi_parser::mgr::ShellForm;
|
||||
use yazi_proxy::TasksProxy;
|
||||
|
|
@ -25,7 +25,10 @@ impl Actor for Shell {
|
|||
let selected: Vec<_> = cx.tab().hovered_and_selected().cloned().map(Into::into).collect();
|
||||
|
||||
let input = if form.interactive {
|
||||
Some(input!(cx, InputCfg::shell(form.block).with_value(&*form.run).with_cursor(form.cursor))?)
|
||||
Some(input!(
|
||||
cx,
|
||||
YAZI.input.shell(form.block).with_value(&*form.run).with_cursor(form.cursor)
|
||||
)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use anyhow::Result;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_config::YAZI;
|
||||
use yazi_macro::{act, input, render, succ};
|
||||
use yazi_parser::mgr::TabRenameForm;
|
||||
use yazi_proxy::MgrProxy;
|
||||
|
|
@ -29,7 +29,7 @@ impl Actor for TabRename {
|
|||
|
||||
let mut input = input!(
|
||||
cx,
|
||||
InputCfg::tab_rename().with_value(form.name.unwrap_or(Cow::Borrowed(&pref.name)))
|
||||
YAZI.input.tab_rename().with_value(form.name.unwrap_or(Cow::Borrowed(&pref.name)))
|
||||
)?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ use yazi_macro::{succ, writef};
|
|||
use yazi_parser::VoidForm;
|
||||
use yazi_scheduler::AppProxy;
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_term::{TERM, YIELD_TO_SUBPROCESS, sequence::EraseScreen};
|
||||
use yazi_tty::TTY;
|
||||
use yazi_term::{TERM, YIELD_TO_SUBPROCESS};
|
||||
use yazi_tty::{TTY, sequence::EraseScreen};
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,15 @@ yazi-fs = { path = "../yazi-fs", version = "26.5.6" }
|
|||
yazi-macro = { path = "../yazi-macro", version = "26.5.6" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "26.5.6" }
|
||||
yazi-shim = { path = "../yazi-shim", version = "26.5.6" }
|
||||
yazi-term = { path = "../yazi-term", version = "26.5.6" }
|
||||
yazi-tty = { path = "../yazi-tty", version = "26.5.9" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "26.5.6" }
|
||||
|
||||
# External dependencies
|
||||
ansi-to-tui = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
image = { version = "0.25.10", default-features = false, features = [ "avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp" ] }
|
||||
image = { workspace = true }
|
||||
inventory = { workspace = true }
|
||||
moxcms = "0.8.1"
|
||||
palette = { version = "0.7.6", default-features = false }
|
||||
quantette = { version = "0.6.0", default-features = false }
|
||||
|
|
|
|||
|
|
@ -1,105 +1,56 @@
|
|||
use std::{env, path::PathBuf};
|
||||
use std::{fmt::{self, Debug}, ops::Deref};
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui::layout::Rect;
|
||||
use strum::{Display, IntoStaticStr};
|
||||
use tracing::warn;
|
||||
use yazi_emulator::{Emulator, TMUX};
|
||||
use yazi_shared::env_exists;
|
||||
use yazi_emulator::EMULATOR;
|
||||
use yazi_shim::cell::SyncCell;
|
||||
use yazi_widgets::clear::ClearInventory;
|
||||
|
||||
use crate::{Adapters, SHOWN, drivers};
|
||||
use crate::{ADAPTOR, drivers::{Driver, Drivers}};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Display, Eq, IntoStaticStr, PartialEq)]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum Adapter {
|
||||
Kgp,
|
||||
KgpOld,
|
||||
Iip,
|
||||
Sixel,
|
||||
pub struct Adapter {
|
||||
driver: Driver,
|
||||
shown: SyncCell<Option<Rect>>,
|
||||
pub collision: SyncCell<bool>,
|
||||
}
|
||||
|
||||
// Supported by Überzug++
|
||||
X11,
|
||||
Wayland,
|
||||
Chafa,
|
||||
impl Deref for Adapter {
|
||||
type Target = Driver;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.driver }
|
||||
}
|
||||
|
||||
impl Debug for Adapter {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.driver.fmt(f) }
|
||||
}
|
||||
|
||||
impl Adapter {
|
||||
pub async fn image_show<P>(self, path: P, max: Rect) -> Result<Rect>
|
||||
where
|
||||
P: Into<PathBuf>,
|
||||
{
|
||||
if max.is_empty() {
|
||||
return Ok(Rect::default());
|
||||
}
|
||||
|
||||
let path = path.into();
|
||||
match self {
|
||||
Self::Kgp => drivers::Kgp::image_show(path, max).await,
|
||||
Self::KgpOld => drivers::KgpOld::image_show(path, max).await,
|
||||
Self::Iip => drivers::Iip::image_show(path, max).await,
|
||||
Self::Sixel => drivers::Sixel::image_show(path, max).await,
|
||||
Self::X11 | Self::Wayland => drivers::Ueberzug::image_show(path, max).await,
|
||||
Self::Chafa => drivers::Chafa::image_show(path, max).await,
|
||||
pub(super) fn new() -> Self {
|
||||
Self {
|
||||
driver: Drivers::matches(&EMULATOR),
|
||||
shown: SyncCell::new(None),
|
||||
collision: SyncCell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_hide(self) -> Result<()> {
|
||||
if let Some(area) = SHOWN.replace(None) { self.image_erase(area) } else { Ok(()) }
|
||||
pub fn image_hide(&self) -> Result<()> {
|
||||
if let Some(area) = self.shown.replace(None) { self.driver.image_erase(area) } else { Ok(()) }
|
||||
}
|
||||
|
||||
pub fn image_erase(self, area: Rect) -> Result<()> {
|
||||
match self {
|
||||
Self::Kgp => drivers::Kgp::image_erase(area),
|
||||
Self::KgpOld => drivers::KgpOld::image_erase(area),
|
||||
Self::Iip => drivers::Iip::image_erase(area),
|
||||
Self::Sixel => drivers::Sixel::image_erase(area),
|
||||
Self::X11 | Self::Wayland => drivers::Ueberzug::image_erase(area),
|
||||
Self::Chafa => drivers::Chafa::image_erase(area),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn shown_load(self) -> Option<Rect> { SHOWN.get() }
|
||||
|
||||
#[inline]
|
||||
pub(super) fn shown_store(area: Rect) { SHOWN.set(Some(area)); }
|
||||
|
||||
pub(super) fn start(self) { drivers::Ueberzug::start(self); }
|
||||
|
||||
#[inline]
|
||||
pub(super) fn needs_ueberzug(self) -> bool {
|
||||
!matches!(self, Self::Kgp | Self::KgpOld | Self::Iip | Self::Sixel)
|
||||
}
|
||||
pub(super) fn shown_store(&self, area: Rect) { self.shown.set(Some(area)); }
|
||||
}
|
||||
|
||||
impl Adapter {
|
||||
pub fn matches(emulator: &Emulator) -> Self {
|
||||
let mut adapters: Adapters = emulator.into();
|
||||
if env_exists("ZELLIJ_SESSION_NAME") {
|
||||
adapters.retain(|p| *p == Self::Sixel);
|
||||
} else if TMUX.get() {
|
||||
adapters.retain(|p| *p != Self::KgpOld);
|
||||
}
|
||||
if let Some(p) = adapters.first() {
|
||||
return *p;
|
||||
}
|
||||
inventory::submit! {
|
||||
ClearInventory {
|
||||
clear: |area| {
|
||||
let overlap = area.intersection(ADAPTOR.shown.get()?);
|
||||
if overlap.area() == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let supported_compositor = drivers::Ueberzug::supported_compositor();
|
||||
match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
|
||||
"x11" => return Self::X11,
|
||||
"wayland" if supported_compositor => return Self::Wayland,
|
||||
"wayland" if !supported_compositor => return Self::Chafa,
|
||||
_ => warn!("[Adapter] Could not identify XDG_SESSION_TYPE"),
|
||||
}
|
||||
if env_exists("WAYLAND_DISPLAY") {
|
||||
return if supported_compositor { Self::Wayland } else { Self::Chafa };
|
||||
}
|
||||
match env::var("DISPLAY").unwrap_or_default().as_str() {
|
||||
s if !s.is_empty() && !s.contains("/org.xquartz") => return Self::X11,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
warn!("[Adapter] Falling back to chafa");
|
||||
Self::Chafa
|
||||
ADAPTOR.driver.image_erase(overlap).ok();
|
||||
ADAPTOR.collision.set(true);
|
||||
Some(overlap)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::Adapter;
|
||||
|
||||
pub(super) struct Adapters(Vec<Adapter>);
|
||||
|
||||
impl Deref for Adapters {
|
||||
type Target = Vec<Adapter>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl DerefMut for Adapters {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
impl From<&yazi_emulator::Emulator> for Adapters {
|
||||
fn from(value: &yazi_emulator::Emulator) -> Self { value.kind.either_into() }
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Brand> for Adapters {
|
||||
fn from(value: yazi_emulator::Brand) -> Self {
|
||||
use yazi_emulator::Brand as B;
|
||||
|
||||
use crate::Adapter as A;
|
||||
|
||||
Self(match value {
|
||||
B::Kitty => vec![A::Kgp],
|
||||
B::Konsole => vec![A::KgpOld],
|
||||
B::Iterm2 => vec![A::Iip, A::Sixel],
|
||||
B::WezTerm => vec![A::Iip, A::Sixel],
|
||||
B::Foot => vec![A::Sixel],
|
||||
B::Ghostty => vec![A::Kgp],
|
||||
B::Microsoft => vec![A::Sixel],
|
||||
B::Warp => vec![A::Iip, A::KgpOld],
|
||||
B::Rio => vec![A::Kgp],
|
||||
B::BlackBox => vec![A::Sixel],
|
||||
B::VSCode => vec![A::Iip, A::Sixel],
|
||||
B::Tabby => vec![A::Iip, A::Sixel],
|
||||
B::Hyper => vec![A::Iip, A::Sixel],
|
||||
B::Mintty => vec![A::Iip],
|
||||
B::Tmux => vec![],
|
||||
B::VTerm => vec![],
|
||||
B::Apple => vec![],
|
||||
B::Urxvt => vec![],
|
||||
B::Bobcat => vec![A::Iip, A::Sixel],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Unknown> for Adapters {
|
||||
fn from(value: yazi_emulator::Unknown) -> Self {
|
||||
use Adapter as A;
|
||||
|
||||
Self(match (value.kgp, value.sixel) {
|
||||
(true, true) => vec![A::Sixel, A::KgpOld],
|
||||
(true, false) => vec![A::KgpOld],
|
||||
(false, true) => vec![A::Sixel],
|
||||
(false, false) => vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -6,14 +6,14 @@ use ratatui::layout::Rect;
|
|||
use tokio::process::Command;
|
||||
use yazi_config::THEME;
|
||||
use yazi_emulator::Emulator;
|
||||
use yazi_term::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
|
||||
use crate::Adapter;
|
||||
use crate::ADAPTOR;
|
||||
|
||||
pub(crate) struct Chafa;
|
||||
pub(super) struct Chafa;
|
||||
|
||||
impl Chafa {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let child = Command::new("chafa")
|
||||
.args([
|
||||
"-f",
|
||||
|
|
@ -58,8 +58,8 @@ impl Chafa {
|
|||
height: lines.len() as u16,
|
||||
};
|
||||
|
||||
Adapter::Chafa.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((max.x, max.y), |w| {
|
||||
for (i, line) in lines.into_iter().enumerate() {
|
||||
w.write_all(line)?;
|
||||
|
|
@ -69,7 +69,7 @@ impl Chafa {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
|
|
|
|||
59
yazi-adapter/src/drivers/driver.rs
Normal file
59
yazi-adapter/src/drivers/driver.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Result;
|
||||
use ratatui::layout::Rect;
|
||||
use strum::{Display, IntoStaticStr};
|
||||
|
||||
use crate::drivers::{Chafa, Iip, Kgp, KgpOld, Sixel, Ueberzug};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Display, Eq, IntoStaticStr, PartialEq)]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum Driver {
|
||||
Kgp,
|
||||
KgpOld,
|
||||
Iip,
|
||||
Sixel,
|
||||
|
||||
// Supported by Überzug++
|
||||
X11,
|
||||
Wayland,
|
||||
Chafa,
|
||||
}
|
||||
|
||||
impl Driver {
|
||||
pub async fn image_show<P>(self, path: P, max: Rect) -> Result<Rect>
|
||||
where
|
||||
P: Into<PathBuf>,
|
||||
{
|
||||
if max.is_empty() {
|
||||
return Ok(Rect::default());
|
||||
}
|
||||
|
||||
let path = path.into();
|
||||
match self {
|
||||
Self::Kgp => Kgp::image_show(path, max).await,
|
||||
Self::KgpOld => KgpOld::image_show(path, max).await,
|
||||
Self::Iip => Iip::image_show(path, max).await,
|
||||
Self::Sixel => Sixel::image_show(path, max).await,
|
||||
Self::X11 | Self::Wayland => Ueberzug::image_show(path, max).await,
|
||||
Self::Chafa => Chafa::image_show(path, max).await,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_erase(self, area: Rect) -> Result<()> {
|
||||
match self {
|
||||
Self::Kgp => Kgp::image_erase(area),
|
||||
Self::KgpOld => KgpOld::image_erase(area),
|
||||
Self::Iip => Iip::image_erase(area),
|
||||
Self::Sixel => Sixel::image_erase(area),
|
||||
Self::X11 | Self::Wayland => Ueberzug::image_erase(area),
|
||||
Self::Chafa => Chafa::image_erase(area),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn start(self) { Ueberzug::start(self); }
|
||||
|
||||
pub(crate) fn needs_ueberzug(self) -> bool {
|
||||
!matches!(self, Self::Kgp | Self::KgpOld | Self::Iip | Self::Sixel)
|
||||
}
|
||||
}
|
||||
94
yazi-adapter/src/drivers/drivers.rs
Normal file
94
yazi-adapter/src/drivers/drivers.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
use std::{env, ops::{Deref, DerefMut}};
|
||||
|
||||
use tracing::warn;
|
||||
use yazi_emulator::{Emulator, TMUX};
|
||||
use yazi_shared::env_exists;
|
||||
|
||||
use crate::drivers::{Driver as D, Ueberzug};
|
||||
|
||||
pub(crate) struct Drivers(Vec<D>);
|
||||
|
||||
impl Deref for Drivers {
|
||||
type Target = Vec<D>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl DerefMut for Drivers {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
|
||||
}
|
||||
|
||||
impl From<&yazi_emulator::Emulator> for Drivers {
|
||||
fn from(value: &yazi_emulator::Emulator) -> Self { value.kind.either_into() }
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Brand> for Drivers {
|
||||
fn from(value: yazi_emulator::Brand) -> Self {
|
||||
use yazi_emulator::Brand as B;
|
||||
|
||||
Self(match value {
|
||||
B::Kitty => vec![D::Kgp],
|
||||
B::Konsole => vec![D::KgpOld],
|
||||
B::Iterm2 => vec![D::Iip, D::Sixel],
|
||||
B::WezTerm => vec![D::Iip, D::Sixel],
|
||||
B::Foot => vec![D::Sixel],
|
||||
B::Ghostty => vec![D::Kgp],
|
||||
B::Microsoft => vec![D::Sixel],
|
||||
B::Warp => vec![D::Iip, D::KgpOld],
|
||||
B::Rio => vec![D::Kgp],
|
||||
B::BlackBox => vec![D::Sixel],
|
||||
B::VSCode => vec![D::Iip, D::Sixel],
|
||||
B::Tabby => vec![D::Iip, D::Sixel],
|
||||
B::Hyper => vec![D::Iip, D::Sixel],
|
||||
B::Mintty => vec![D::Iip],
|
||||
B::Tmux => vec![],
|
||||
B::VTerm => vec![],
|
||||
B::Apple => vec![],
|
||||
B::Urxvt => vec![],
|
||||
B::Bobcat => vec![D::Iip, D::Sixel],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<yazi_emulator::Unknown> for Drivers {
|
||||
fn from(value: yazi_emulator::Unknown) -> Self {
|
||||
Self(match (value.kgp, value.sixel) {
|
||||
(true, true) => vec![D::Sixel, D::KgpOld],
|
||||
(true, false) => vec![D::KgpOld],
|
||||
(false, true) => vec![D::Sixel],
|
||||
(false, false) => vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drivers {
|
||||
pub fn matches(emulator: &Emulator) -> D {
|
||||
let mut adapters: Self = emulator.into();
|
||||
if env_exists("ZELLIJ_SESSION_NAME") {
|
||||
adapters.retain(|p| *p == D::Sixel);
|
||||
} else if TMUX.get() {
|
||||
adapters.retain(|p| *p != D::KgpOld);
|
||||
}
|
||||
if let Some(p) = adapters.first() {
|
||||
return *p;
|
||||
}
|
||||
|
||||
let supported_compositor = Ueberzug::supported_compositor();
|
||||
match env::var("XDG_SESSION_TYPE").unwrap_or_default().as_str() {
|
||||
"x11" => return D::X11,
|
||||
"wayland" if supported_compositor => return D::Wayland,
|
||||
"wayland" if !supported_compositor => return D::Chafa,
|
||||
_ => warn!("[Adapter] Could not identify XDG_SESSION_TYPE"),
|
||||
}
|
||||
if env_exists("WAYLAND_DISPLAY") {
|
||||
return if supported_compositor { D::Wayland } else { D::Chafa };
|
||||
}
|
||||
match env::var("DISPLAY").unwrap_or_default().as_str() {
|
||||
s if !s.is_empty() && !s.contains("/org.xquartz") => return D::X11,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
warn!("[Adapter] Falling back to chafa");
|
||||
D::Chafa
|
||||
}
|
||||
}
|
||||
|
|
@ -6,27 +6,27 @@ use image::{DynamicImage, ExtendedColorType, ImageEncoder, codecs::{jpeg::JpegEn
|
|||
use ratatui::layout::Rect;
|
||||
use yazi_config::{THEME, YAZI};
|
||||
use yazi_emulator::{CLOSE, Emulator, START};
|
||||
use yazi_term::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
|
||||
use crate::{Image, adapter::Adapter};
|
||||
use crate::{ADAPTOR, Image};
|
||||
|
||||
pub(crate) struct Iip;
|
||||
pub(super) struct Iip;
|
||||
|
||||
impl Iip {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
Adapter::Iip.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((max.x, max.y), |w| {
|
||||
w.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ use ratatui::{layout::Rect, style::Color};
|
|||
use yazi_config::THEME;
|
||||
use yazi_emulator::{CLOSE, ESCAPE, Emulator, START};
|
||||
use yazi_shim::cell::SyncCell;
|
||||
use yazi_term::sequence::{MoveTo, ResetAttrs, SetBg, SetFg};
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg, SetFg};
|
||||
|
||||
use crate::{adapter::Adapter, image::Image};
|
||||
use crate::{ADAPTOR, image::Image};
|
||||
|
||||
static DIACRITICS: [char; 297] = [
|
||||
'\u{0305}',
|
||||
|
|
@ -312,18 +312,18 @@ static DIACRITICS: [char; 297] = [
|
|||
'\u{1D244}',
|
||||
];
|
||||
|
||||
pub(crate) struct Kgp;
|
||||
pub(super) struct Kgp;
|
||||
|
||||
impl Kgp {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
|
||||
let b1 = Self::encode(img).await?;
|
||||
let b2 = Self::place(&area)?;
|
||||
|
||||
Adapter::Kgp.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((area.x, area.y), |w| {
|
||||
w.write_all(&b1)?;
|
||||
w.write_all(&b2)?;
|
||||
|
|
@ -331,7 +331,7 @@ impl Kgp {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
|
|
|
|||
|
|
@ -8,25 +8,25 @@ use ratatui::layout::Rect;
|
|||
use yazi_emulator::{CLOSE, ESCAPE, Emulator, START};
|
||||
use yazi_tty::TTY;
|
||||
|
||||
use crate::{Image, adapter::Adapter};
|
||||
use crate::{ADAPTOR, Image};
|
||||
|
||||
pub(crate) struct KgpOld;
|
||||
pub(super) struct KgpOld;
|
||||
|
||||
impl KgpOld {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
Adapter::KgpOld.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((area.x, area.y), |w| {
|
||||
w.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(_: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(_: Rect) -> Result<()> {
|
||||
let mut w = TTY.lockout();
|
||||
write!(w, "{START}_Gq=2,a=d,d=A{ESCAPE}\\{CLOSE}")?;
|
||||
w.flush()?;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(chafa iip kgp kgp_old sixel ueberzug);
|
||||
yazi_macro::mod_flat!(chafa driver drivers iip kgp kgp_old sixel ueberzug);
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ use quantette::{PaletteSize, color_map::IndexedColorMap, wu::{BinnerU8x3, WuU8x3
|
|||
use ratatui::layout::Rect;
|
||||
use yazi_config::THEME;
|
||||
use yazi_emulator::{CLOSE, ESCAPE, Emulator, START};
|
||||
use yazi_term::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
use yazi_tty::sequence::{MoveTo, ResetAttrs, SetBg};
|
||||
|
||||
use crate::{Image, adapter::Adapter};
|
||||
use crate::{ADAPTOR, Image};
|
||||
|
||||
pub(crate) struct Sixel;
|
||||
pub(super) struct Sixel;
|
||||
|
||||
struct QuantizeOutput<T> {
|
||||
indices: Vec<u8>,
|
||||
|
|
@ -19,20 +19,20 @@ struct QuantizeOutput<T> {
|
|||
}
|
||||
|
||||
impl Sixel {
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let img = Image::downscale(path, max).await?;
|
||||
let area = Image::pixel_area((img.width(), img.height()), max);
|
||||
let b = Self::encode(img).await?;
|
||||
|
||||
Adapter::Sixel.image_hide()?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.image_hide()?;
|
||||
ADAPTOR.shown_store(area);
|
||||
Emulator::move_lock((area.x, area.y), |w| {
|
||||
w.write_all(&b)?;
|
||||
Ok(area)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(area: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(area: Rect) -> Result<()> {
|
||||
let s = " ".repeat(area.width as usize);
|
||||
Emulator::move_lock((0, 0), |w| {
|
||||
if let Some(c) = THEME.app.overall.get().bg {
|
||||
|
|
|
|||
|
|
@ -10,21 +10,21 @@ use yazi_emulator::Dimension;
|
|||
use yazi_shared::{LOG_LEVEL, env_exists};
|
||||
use yazi_shim::{cell::RoCell, strum::IntoStr};
|
||||
|
||||
use crate::Adapter;
|
||||
use crate::{ADAPTOR, drivers::Driver};
|
||||
|
||||
type Cmd = Option<(PathBuf, Rect)>;
|
||||
|
||||
static DEMON: RoCell<Option<UnboundedSender<Cmd>>> = RoCell::new();
|
||||
|
||||
pub(crate) struct Ueberzug;
|
||||
pub(super) struct Ueberzug;
|
||||
|
||||
impl Ueberzug {
|
||||
pub(crate) fn start(adapter: Adapter) {
|
||||
if !adapter.needs_ueberzug() {
|
||||
pub(super) fn start(driver: Driver) {
|
||||
if !driver.needs_ueberzug() {
|
||||
return DEMON.init(None);
|
||||
}
|
||||
|
||||
let mut child = Self::create_demon(adapter).ok();
|
||||
let mut child = Self::create_demon(driver).ok();
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
|
||||
tokio::spawn(async move {
|
||||
|
|
@ -34,17 +34,17 @@ impl Ueberzug {
|
|||
child = None;
|
||||
}
|
||||
if child.is_none() {
|
||||
child = Self::create_demon(adapter).ok();
|
||||
child = Self::create_demon(driver).ok();
|
||||
}
|
||||
if let Some(c) = &mut child {
|
||||
Self::send_command(adapter, c, cmd).await.ok();
|
||||
Self::send_command(driver, c, cmd).await.ok();
|
||||
}
|
||||
}
|
||||
});
|
||||
DEMON.init(Some(tx))
|
||||
}
|
||||
|
||||
pub(crate) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
pub(super) async fn image_show(path: PathBuf, max: Rect) -> Result<Rect> {
|
||||
let Some(tx) = &*DEMON else {
|
||||
bail!("uninitialized ueberzugpp");
|
||||
};
|
||||
|
|
@ -64,11 +64,11 @@ impl Ueberzug {
|
|||
.unwrap_or(max);
|
||||
|
||||
tx.send(Some((path, area)))?;
|
||||
Adapter::shown_store(area);
|
||||
ADAPTOR.shown_store(area);
|
||||
Ok(area)
|
||||
}
|
||||
|
||||
pub(crate) fn image_erase(_: Rect) -> Result<()> {
|
||||
pub(super) fn image_erase(_: Rect) -> Result<()> {
|
||||
if let Some(tx) = &*DEMON {
|
||||
Ok(tx.send(None)?)
|
||||
} else {
|
||||
|
|
@ -79,16 +79,16 @@ impl Ueberzug {
|
|||
// Currently Überzug++'s Wayland output only supports Niri, Sway, Hyprland and
|
||||
// Wayfire as it requires information from specific compositor socket directly.
|
||||
// These environment variables are from ueberzugpp src/canvas/wayland/config.cpp
|
||||
pub(crate) fn supported_compositor() -> bool {
|
||||
pub(super) fn supported_compositor() -> bool {
|
||||
env_exists("NIRI_SOCKET")
|
||||
|| env_exists("SWAYSOCK")
|
||||
|| env_exists("HYPRLAND_INSTANCE_SIGNATURE")
|
||||
|| env_exists("WAYFIRE_SOCKET")
|
||||
}
|
||||
|
||||
fn create_demon(adapter: Adapter) -> Result<Child> {
|
||||
fn create_demon(driver: Driver) -> Result<Child> {
|
||||
let result = Command::new("ueberzugpp")
|
||||
.args(["layer", "-so", adapter.into_str()])
|
||||
.args(["layer", "-so", driver.into_str()])
|
||||
.env("SPDLOG_LEVEL", if LOG_LEVEL.get().is_none() { "" } else { "debug" })
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::piped())
|
||||
|
|
@ -113,7 +113,7 @@ impl Ueberzug {
|
|||
rect
|
||||
}
|
||||
|
||||
async fn send_command(adapter: Adapter, child: &mut Child, cmd: Cmd) -> Result<()> {
|
||||
async fn send_command(driver: Driver, child: &mut Child, cmd: Cmd) -> Result<()> {
|
||||
let s = if let Some((path, rect)) = cmd {
|
||||
debug!("ueberzugpp rect before adjustment: {:?}", rect);
|
||||
let rect = Self::adjust_rect(rect);
|
||||
|
|
@ -132,7 +132,7 @@ impl Ueberzug {
|
|||
format!(r#"{{"action":"remove","identifier":"yazi"}}{}"#, '\n')
|
||||
};
|
||||
|
||||
debug!("`ueberzugpp layer -so {adapter}` command: {s}");
|
||||
debug!("`ueberzugpp layer -so {driver}` command: {s}");
|
||||
child.stdin.as_mut().unwrap().write_all(s.as_bytes()).await?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use image::{ColorType, DynamicImage, GrayAlphaImage, GrayImage, ImageDecoder, Rg
|
|||
use moxcms::{CicpColorPrimaries, ColorProfile, DataColorSpace, Layout, TransferCharacteristics, TransformOptions};
|
||||
|
||||
pub(super) struct Icc;
|
||||
|
||||
impl Icc {
|
||||
pub(super) fn transform(mut decoder: impl ImageDecoder) -> anyhow::Result<DynamicImage> {
|
||||
if let Some(layout) = Self::color_type_to_layout(decoder.color_type())
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use image::{ImageDecoder, ImageError};
|
||||
|
||||
pub type ImageFormat = image::ImageFormat;
|
||||
pub type ImageColor = image::ColorType;
|
||||
pub type ImageOrientation = image::metadata::Orientation;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImageInfo {
|
||||
pub format: ImageFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub color: ImageColor,
|
||||
pub orientation: Option<ImageOrientation>,
|
||||
}
|
||||
|
||||
impl ImageInfo {
|
||||
pub async fn new(path: PathBuf) -> image::ImageResult<Self> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let reader = image::ImageReader::open(path)?.with_guessed_format()?;
|
||||
|
||||
let Some(format) = reader.format() else {
|
||||
return Err(ImageError::IoError(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"unknown image format",
|
||||
)));
|
||||
};
|
||||
|
||||
let mut decoder = reader.into_decoder()?;
|
||||
let (width, height) = decoder.dimensions();
|
||||
Ok(Self {
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
color: decoder.color_type(),
|
||||
orientation: decoder.orientation().ok(),
|
||||
})
|
||||
})
|
||||
.await
|
||||
.map_err(|e| ImageError::IoError(e.into()))?
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,12 @@
|
|||
yazi_macro::mod_pub!(drivers);
|
||||
|
||||
yazi_macro::mod_flat!(adapter adapters icc image info);
|
||||
yazi_macro::mod_flat!(adapter icc image);
|
||||
|
||||
use yazi_emulator::{Brand, CLOSE, EMULATOR, ESCAPE, Emulator, Mux, START, TMUX};
|
||||
use yazi_shared::in_wsl;
|
||||
use yazi_shim::cell::SyncCell;
|
||||
use yazi_shim::cell::{RoCell, SyncCell};
|
||||
|
||||
pub static ADAPTOR: SyncCell<Adapter> = SyncCell::new(Adapter::Chafa);
|
||||
|
||||
// Image state
|
||||
static SHOWN: SyncCell<Option<ratatui::layout::Rect>> = SyncCell::new(None);
|
||||
pub static ADAPTOR: RoCell<Adapter> = RoCell::new();
|
||||
|
||||
// WSL support
|
||||
pub static WSL: SyncCell<bool> = SyncCell::new(false);
|
||||
|
|
@ -34,7 +31,7 @@ pub fn init() -> anyhow::Result<()> {
|
|||
EMULATOR.init(emulator);
|
||||
yazi_config::init_flavor(EMULATOR.light)?;
|
||||
|
||||
ADAPTOR.set(Adapter::matches(&EMULATOR));
|
||||
ADAPTOR.get().start();
|
||||
ADAPTOR.init(Adapter::new());
|
||||
ADAPTOR.start();
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,33 +17,24 @@ default = [ "vendored-lua" ]
|
|||
vendored-lua = [ "mlua/vendored" ]
|
||||
|
||||
[dependencies]
|
||||
yazi-adapter = { path = "../yazi-adapter", version = "26.5.6" }
|
||||
yazi-codegen = { path = "../yazi-codegen", version = "26.5.6" }
|
||||
yazi-config = { path = "../yazi-config", version = "26.5.6" }
|
||||
yazi-fs = { path = "../yazi-fs", version = "26.5.6" }
|
||||
yazi-macro = { path = "../yazi-macro", version = "26.5.6" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "26.5.6" }
|
||||
yazi-shim = { path = "../yazi-shim", version = "26.5.6" }
|
||||
yazi-term = { path = "../yazi-term", version = "26.5.6" }
|
||||
yazi-tty = { path = "../yazi-tty", version = "26.5.9" }
|
||||
yazi-vfs = { path = "../yazi-vfs", version = "26.5.6" }
|
||||
yazi-widgets = { path = "../yazi-widgets", version = "26.5.6" }
|
||||
|
||||
# External dependencies
|
||||
ansi-to-tui = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
hashbrown = { workspace = true }
|
||||
image = { workspace = true }
|
||||
inventory = { workspace = true }
|
||||
mlua = { workspace = true }
|
||||
ordered-float = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
paste = { workspace = true }
|
||||
ratatui = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tokio-stream = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
use mlua::{AnyUserData, IntoLuaMulti, UserData, UserDataMethods, Value};
|
||||
use yazi_fs::provider::FileBuilder;
|
||||
|
||||
use crate::{Error, Fd, UrlRef};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Access(yazi_vfs::provider::Gate);
|
||||
|
||||
impl UserData for Access {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_function("append", |_, (ud, append): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.append(append);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("create", |_, (ud, create): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.create(create);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("create_new", |_, (ud, create_new): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.create_new(create_new);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_async_method("open", |lua, me, url: UrlRef| async move {
|
||||
match me.0.open(&*url).await {
|
||||
Ok(fd) => Fd(fd).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
});
|
||||
methods.add_function("read", |_, (ud, read): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.read(read);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("truncate", |_, (ud, truncate): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.truncate(truncate);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("write", |_, (ud, write): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.write(write);
|
||||
Ok(ud)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -5,10 +5,9 @@ pub type ComposerGet = fn(&Lua, &[u8]) -> mlua::Result<Value>;
|
|||
pub type ComposerSet = fn(&Lua, &[u8], Value) -> mlua::Result<Value>;
|
||||
|
||||
pub struct Composer<G, S> {
|
||||
get: G,
|
||||
set: S,
|
||||
parent: Option<(G, S)>,
|
||||
cache: HashMap<Vec<u8>, Value>,
|
||||
get: G,
|
||||
set: S,
|
||||
cache: HashMap<Vec<u8>, Value>,
|
||||
}
|
||||
|
||||
impl<G, S> Composer<G, S>
|
||||
|
|
@ -16,13 +15,7 @@ where
|
|||
G: Fn(&Lua, &[u8]) -> mlua::Result<Value> + 'static,
|
||||
S: Fn(&Lua, &[u8], Value) -> mlua::Result<Value> + 'static,
|
||||
{
|
||||
#[inline]
|
||||
pub fn new(get: G, set: S) -> Self { Self { get, set, parent: None, cache: Default::default() } }
|
||||
|
||||
#[inline]
|
||||
pub fn with_parent(get: G, set: S, p_get: G, p_set: S) -> Self {
|
||||
Self { get, set, parent: Some((p_get, p_set)), cache: Default::default() }
|
||||
}
|
||||
pub fn new(get: G, set: S) -> Self { Self { get, set, cache: Default::default() } }
|
||||
}
|
||||
|
||||
impl<G, S> UserData for Composer<G, S>
|
||||
|
|
@ -37,14 +30,9 @@ where
|
|||
return Ok(v.clone());
|
||||
}
|
||||
|
||||
let mut value = (me.get)(lua, &key)?;
|
||||
if value.is_nil()
|
||||
&& let Some((p_get, _)) = &me.parent
|
||||
{
|
||||
value = p_get(lua, &key)?;
|
||||
}
|
||||
|
||||
let value = (me.get)(lua, &key)?;
|
||||
me.cache.insert(key.to_owned(), value.clone());
|
||||
|
||||
Ok(value)
|
||||
});
|
||||
|
||||
|
|
@ -56,11 +44,6 @@ where
|
|||
|
||||
if value.is_nil() {
|
||||
me.cache.remove(key.as_ref());
|
||||
} else if let Some((_, p_set)) = &me.parent {
|
||||
match p_set(lua, key.as_ref(), value)? {
|
||||
Value::Nil => me.cache.remove(key.as_ref()),
|
||||
v => me.cache.insert(key.to_owned(), v),
|
||||
};
|
||||
} else {
|
||||
me.cache.insert(key.to_owned(), value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::{FileRef, Id, Iter};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Fetcher {
|
||||
inner: Arc<yazi_config::plugin::Fetcher>,
|
||||
}
|
||||
|
||||
impl Deref for Fetcher {
|
||||
type Target = yazi_config::plugin::Fetcher;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Fetcher {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Fetcher>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Fetcher {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
fields.add_cached_field("name", |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct FetcherMatcher(yazi_config::plugin::FetcherMatcher<'static>);
|
||||
|
||||
impl FetcherMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::FetcherMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for FetcherMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::FetcherMatcher {
|
||||
fetchers: YAZI.plugin.fetchers.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for FetcherMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of FetcherMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for FetcherMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Fetcher::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
use mlua::{IntoLua, MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::config::FetcherMatcher;
|
||||
|
||||
pub struct Fetchers;
|
||||
|
||||
impl UserData for Fetchers {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<FetcherMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => FetcherMatcher::new(&YAZI.plugin.fetchers).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.plugin.fetchers.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
yazi_macro::mod_flat!(fetcher fetchers open_rule open_rules opener opener_rule opener_rules preloader preloaders previewer previewers spotter spotters);
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, LuaSerdeExt, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::{FileRef, Id, Iter};
|
||||
|
||||
pub struct OpenRule {
|
||||
inner: Arc<yazi_config::open::OpenRule>,
|
||||
}
|
||||
|
||||
impl Deref for OpenRule {
|
||||
type Target = Arc<yazi_config::open::OpenRule>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<OpenRule> for Arc<yazi_config::open::OpenRule> {
|
||||
fn from(value: OpenRule) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl OpenRule {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::open::OpenRule>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenRule {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
Ok(Self::new(lua.from_value::<yazi_config::open::OpenRule>(value)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for OpenRule {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
fields.add_cached_field("use", |lua, me| {
|
||||
lua.create_sequence_from(me.r#use.iter().map(|s| s.as_str()))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct OpenRuleMatcher(pub(super) yazi_config::open::OpenRuleMatcher<'static>);
|
||||
|
||||
impl OpenRuleMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::open::OpenRuleMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for OpenRuleMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::open::OpenRuleMatcher {
|
||||
rules: YAZI.open.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenRuleMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of OpenRuleMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for OpenRuleMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(OpenRule::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
use mlua::{ExternalError, ExternalResult, IntoLua, MetaMethod, Table, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shim::mlua::DeserializeOverLua;
|
||||
|
||||
use crate::config::{OpenRule, OpenRuleMatcher};
|
||||
|
||||
pub struct OpenRules;
|
||||
|
||||
impl UserData for OpenRules {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<OpenRuleMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => OpenRuleMatcher::new(&*YAZI.open).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_method("insert", |_, _, (index, rule): (isize, OpenRule)| {
|
||||
let index = match index {
|
||||
1.. => index - 1,
|
||||
0 => return Err("index must be 1-based or negative".into_lua_err()),
|
||||
_ => index,
|
||||
};
|
||||
|
||||
YAZI.open.insert(index, rule.clone()).into_lua_err()?;
|
||||
Ok(rule)
|
||||
});
|
||||
|
||||
methods.add_method("remove", |_, _, matcher: OpenRuleMatcher| {
|
||||
YAZI.open.remove(matcher.0);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("update", |_, _, (matcher, table): (OpenRuleMatcher, Table)| {
|
||||
YAZI.open.update(matcher.0, |rule| rule.deserialize_over_lua(&table))?;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.open.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
use mlua::{ExternalError, FromLua, IntoLua, IntoLuaMulti, MetaMethod, UserData, UserDataMethods, Value};
|
||||
use yazi_config::{YAZI, opener::OpenerRulesMatcher};
|
||||
|
||||
use crate::config::OpenerRules;
|
||||
|
||||
pub struct Opener;
|
||||
|
||||
impl UserData for Opener {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::Index, |lua, _, key: mlua::String| {
|
||||
let key = key.to_str()?;
|
||||
match YAZI.opener.load().get(&*key) {
|
||||
Some(rules) => OpenerRules::new(rules.clone()).into_lua(lua),
|
||||
None => Ok(Value::Nil),
|
||||
}
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::NewIndex, |lua, _, (key, value): (mlua::String, Value)| {
|
||||
let key = key.to_str()?;
|
||||
match value {
|
||||
t @ Value::Table(_) => {
|
||||
YAZI.opener.insert(&key, &*OpenerRules::from_lua(t, lua)?);
|
||||
}
|
||||
Value::Nil => {
|
||||
YAZI.opener.remove(&key);
|
||||
}
|
||||
_ => return Err("expected a table or nil".into_lua_err()),
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Pairs, |lua, _, ()| {
|
||||
let mut matcher = OpenerRulesMatcher::from(&YAZI.opener);
|
||||
let iter = lua.create_function_mut(move |lua, ()| {
|
||||
if let Some((name, rules)) = matcher.next() {
|
||||
(name, OpenerRules::new(rules)).into_lua_multi(lua)
|
||||
} else {
|
||||
().into_lua_multi(lua)
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(iter)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, LuaSerdeExt, Table, UserData, UserDataFields, Value};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::{Id, Iter};
|
||||
|
||||
pub struct OpenerRule {
|
||||
inner: Arc<yazi_config::opener::OpenerRule>,
|
||||
}
|
||||
|
||||
impl Deref for OpenerRule {
|
||||
type Target = Arc<yazi_config::opener::OpenerRule>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<OpenerRule> for Arc<yazi_config::opener::OpenerRule> {
|
||||
fn from(value: OpenerRule) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl OpenerRule {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::opener::OpenerRule>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenerRule {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
let mut inner: yazi_config::opener::OpenerRule = lua.from_value(value)?;
|
||||
inner.fill();
|
||||
|
||||
Ok(Self::new(inner))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for OpenerRule {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
fields.add_cached_field("run", |lua, me| lua.create_string(&*me.run));
|
||||
fields.add_field_method_get("block", |_, me| Ok(me.block));
|
||||
fields.add_field_method_get("orphan", |_, me| Ok(me.orphan));
|
||||
fields.add_cached_field("desc", |lua, me| lua.create_string(&*me.desc));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct OpenerRuleMatcher(pub(super) yazi_config::opener::OpenerRuleMatcher);
|
||||
|
||||
impl OpenerRuleMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::opener::OpenerRuleMatcher>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for OpenerRuleMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(t: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = t.raw_get("id").unwrap_or_default();
|
||||
|
||||
Ok(Self(yazi_config::opener::OpenerRuleMatcher { id: id.0, ..Default::default() }))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenerRuleMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of OpenerRuleMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for OpenerRuleMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(OpenerRule::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, ExternalResult, FromLua, IntoLua, Lua, LuaSerdeExt, MetaMethod, UserData, UserDataMethods, Value};
|
||||
use yazi_shim::toml::DeserializeOverHook;
|
||||
|
||||
use crate::config::{OpenerRule, OpenerRuleMatcher};
|
||||
|
||||
pub struct OpenerRules {
|
||||
inner: Arc<yazi_config::opener::OpenerRules>,
|
||||
}
|
||||
|
||||
impl Deref for OpenerRules {
|
||||
type Target = Arc<yazi_config::opener::OpenerRules>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl OpenerRules {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::opener::OpenerRules>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for OpenerRules {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
let inner: yazi_config::opener::OpenerRules = lua.from_value(value)?;
|
||||
|
||||
Ok(Self::new(inner.deserialize_over_hook().into_lua_err()?))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for OpenerRules {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, me, matcher: Option<OpenerRuleMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => OpenerRuleMatcher::new(&*me.inner).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_method("insert", |_, me, (index, rule): (isize, OpenerRule)| {
|
||||
let index = match index {
|
||||
1.. => index - 1,
|
||||
0 => return Err("index must be 1-based or negative".into_lua_err()),
|
||||
_ => index,
|
||||
};
|
||||
|
||||
me.inner.insert(index, rule.clone()).into_lua_err()?;
|
||||
Ok(rule)
|
||||
});
|
||||
|
||||
methods.add_method("remove", |_, me, matcher: OpenerRuleMatcher| {
|
||||
me.inner.remove(matcher.0);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.inner.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::{FileRef, Id, Iter};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Preloader {
|
||||
inner: Arc<yazi_config::plugin::Preloader>,
|
||||
}
|
||||
|
||||
impl Deref for Preloader {
|
||||
type Target = yazi_config::plugin::Preloader;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Preloader {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Preloader>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Preloader {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
fields.add_cached_field("name", |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct PreloaderMatcher(pub(super) yazi_config::plugin::PreloaderMatcher<'static>);
|
||||
|
||||
impl PreloaderMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::PreloaderMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for PreloaderMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::PreloaderMatcher {
|
||||
preloaders: YAZI.plugin.preloaders.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for PreloaderMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of PreloaderMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for PreloaderMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Preloader::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
use mlua::{IntoLua, MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::config::PreloaderMatcher;
|
||||
|
||||
pub struct Preloaders;
|
||||
|
||||
impl UserData for Preloaders {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<PreloaderMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => PreloaderMatcher::new(&YAZI.plugin.preloaders).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.plugin.preloaders.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, LuaSerdeExt, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::{FileRef, Id, Iter};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Previewer {
|
||||
inner: Arc<yazi_config::plugin::Previewer>,
|
||||
}
|
||||
|
||||
impl Deref for Previewer {
|
||||
type Target = yazi_config::plugin::Previewer;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<Previewer> for Arc<yazi_config::plugin::Previewer> {
|
||||
fn from(value: Previewer) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl Previewer {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Previewer>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Previewer {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
Ok(Self::new(lua.from_value::<yazi_config::plugin::Previewer>(value)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Previewer {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
fields.add_cached_field("name", |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct PreviewerMatcher(pub(super) yazi_config::plugin::PreviewerMatcher<'static>);
|
||||
|
||||
impl PreviewerMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::PreviewerMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for PreviewerMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::PreviewerMatcher {
|
||||
previewers: YAZI.plugin.previewers.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for PreviewerMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of PreviewerMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for PreviewerMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Previewer::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
use mlua::{ExternalError, ExternalResult, IntoLua, MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::config::{Previewer, PreviewerMatcher};
|
||||
|
||||
pub struct Previewers;
|
||||
|
||||
impl UserData for Previewers {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<PreviewerMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => PreviewerMatcher::new(&YAZI.plugin.previewers).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_method("insert", |_, _, (index, previewer): (isize, Previewer)| {
|
||||
let index = match index {
|
||||
1.. => index - 1,
|
||||
0 => return Err("index must be 1-based or negative".into_lua_err()),
|
||||
_ => index,
|
||||
};
|
||||
|
||||
YAZI.plugin.previewers.insert(index, previewer.clone().into()).into_lua_err()?;
|
||||
Ok(previewer)
|
||||
});
|
||||
|
||||
methods.add_method("remove", |_, _, matcher: PreviewerMatcher| {
|
||||
YAZI.plugin.previewers.remove(matcher.0);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.plugin.previewers.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, Value};
|
||||
use yazi_config::YAZI;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::{FileRef, Id, Iter};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Spotter {
|
||||
inner: Arc<yazi_config::plugin::Spotter>,
|
||||
}
|
||||
|
||||
impl Deref for Spotter {
|
||||
type Target = yazi_config::plugin::Spotter;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Spotter {
|
||||
pub fn new(inner: impl Into<Arc<yazi_config::plugin::Spotter>>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Spotter {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.id)));
|
||||
|
||||
fields.add_cached_field("name", |lua, me| lua.create_string(&*me.name));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct SpotterMatcher(pub(super) yazi_config::plugin::SpotterMatcher<'static>);
|
||||
|
||||
impl SpotterMatcher {
|
||||
pub fn new(inner: impl Into<yazi_config::plugin::SpotterMatcher<'static>>) -> Self {
|
||||
Self(inner.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for SpotterMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
let file: Option<FileRef> = value.raw_get("file")?;
|
||||
let mime: Option<String> = value.raw_get("mime")?;
|
||||
|
||||
Ok(Self(yazi_config::plugin::SpotterMatcher {
|
||||
spotters: YAZI.plugin.spotters.load_full(),
|
||||
id: id.0,
|
||||
file: file.map(|f| f.inner.clone().into()),
|
||||
mime: mime.map(Into::into),
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for SpotterMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of SpotterMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for SpotterMatcher {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Spotter::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
use mlua::{IntoLua, MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_config::YAZI;
|
||||
|
||||
use crate::config::SpotterMatcher;
|
||||
|
||||
pub struct Spotters;
|
||||
|
||||
impl UserData for Spotters {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |lua, _, matcher: Option<SpotterMatcher>| match matcher {
|
||||
Some(matcher) => matcher.into_lua(lua),
|
||||
None => SpotterMatcher::new(&YAZI.plugin.spotters).into_lua(lua),
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, _, ()| Ok(YAZI.plugin.spotters.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
use std::{mem, ops::Deref};
|
||||
|
||||
use mlua::{IntoLua, UserData, UserDataFields, Value};
|
||||
use yazi_shim::{mlua::UserDataFieldsExt, strum::IntoStr};
|
||||
use yazi_term::event::{DndDropArrive, DndEvent as Inner};
|
||||
|
||||
pub struct DndEvent {
|
||||
inner: Inner,
|
||||
}
|
||||
|
||||
impl Deref for DndEvent {
|
||||
type Target = Inner;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<Inner> for DndEvent {
|
||||
fn from(inner: Inner) -> Self { Self { inner } }
|
||||
}
|
||||
|
||||
impl UserData for DndEvent {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("type", |_, me| Ok(me.inner.r#type()));
|
||||
|
||||
fields.add_field_method_get("x", |_, me| Ok(me.inner.x()));
|
||||
|
||||
fields.add_field_method_get("y", |_, me| Ok(me.inner.y()));
|
||||
|
||||
fields.add_field_method_get("idx", |_, me| Ok(me.inner.idx()));
|
||||
|
||||
fields.add_field_method_get("op", |_, me| Ok(me.inner.op().map(IntoStr::into_str)));
|
||||
|
||||
fields.add_cached_field("mimes", |lua, me| {
|
||||
if let Some(mimes) = me.inner.mimes() {
|
||||
lua.create_sequence_from(mimes.iter())?.into_lua(lua)
|
||||
} else {
|
||||
Ok(Value::Nil)
|
||||
}
|
||||
});
|
||||
|
||||
fields.add_cached_field_mut("data", |lua, me| match &mut me.inner {
|
||||
Inner::DropArrive(DndDropArrive { data, .. }) => {
|
||||
lua.create_external_string(mem::take(data))?.into_lua(lua)
|
||||
}
|
||||
_ => Ok(Value::Nil),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ use std::fmt::Debug;
|
|||
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
|
||||
use super::{Pos, Rect};
|
||||
use crate::position::Position;
|
||||
|
||||
const EXPECTED: &str = "expected a Pos or Rect";
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ impl Area {
|
|||
|
||||
pub fn transform(
|
||||
self,
|
||||
f: impl FnOnce(yazi_config::popup::Position) -> ratatui::layout::Rect,
|
||||
f: impl FnOnce(Position) -> ratatui::layout::Rect,
|
||||
) -> ratatui::layout::Rect {
|
||||
match self {
|
||||
Self::Rect(rect) => *rect,
|
||||
|
|
@ -62,8 +63,8 @@ impl From<ratatui::layout::Rect> for Area {
|
|||
fn from(rect: ratatui::layout::Rect) -> Self { Self::Rect(rect.into()) }
|
||||
}
|
||||
|
||||
impl From<yazi_config::popup::Position> for Area {
|
||||
fn from(pos: yazi_config::popup::Position) -> Self { Self::Pos(pos.into()) }
|
||||
impl From<Position> for Area {
|
||||
fn from(value: Position) -> Self { Self::Pos(value.into()) }
|
||||
}
|
||||
|
||||
impl TryFrom<&AnyUserData> for Area {
|
||||
|
|
|
|||
|
|
@ -36,15 +36,6 @@ impl Spatial for Bar {
|
|||
fn set_area(&mut self, area: Area) { self.area = area; }
|
||||
}
|
||||
|
||||
impl Widget for Bar {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
(&self).render(rect, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &Bar {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
use mlua::{IntoLua, Lua, Value};
|
||||
|
||||
use crate::{Composer, ComposerGet, ComposerSet};
|
||||
|
||||
pub fn compose(p_get: ComposerGet, p_set: ComposerSet) -> Composer<ComposerGet, ComposerSet> {
|
||||
fn get(lua: &Lua, key: &[u8]) -> mlua::Result<Value> {
|
||||
match key {
|
||||
b"Align" => super::Align::compose(lua)?,
|
||||
b"Bar" => super::Bar::compose(lua)?,
|
||||
b"Border" => super::Border::compose(lua)?,
|
||||
b"Clear" => super::Clear::compose(lua)?,
|
||||
b"Color" => super::Color::compose(lua)?,
|
||||
b"Constraint" => super::Constraint::compose(lua)?,
|
||||
b"Edge" => super::Edge::compose(lua)?,
|
||||
b"Fill" => super::Fill::compose(lua)?,
|
||||
b"Gauge" => super::Gauge::compose(lua)?,
|
||||
b"Input" => super::Input::compose(lua)?,
|
||||
b"Layout" => super::Layout::compose(lua)?,
|
||||
b"Line" => super::Line::compose(lua)?,
|
||||
b"List" => super::List::compose(lua)?,
|
||||
b"Pad" => super::Pad::compose(lua)?,
|
||||
b"Pos" => super::Pos::compose(lua)?,
|
||||
b"Rect" => super::Rect::compose(lua)?,
|
||||
b"Row" => super::Row::compose(lua)?,
|
||||
b"Span" => super::Span::compose(lua)?,
|
||||
b"Style" => crate::Style::compose(lua)?,
|
||||
b"Table" => super::Table::compose(lua)?,
|
||||
b"Text" => super::Text::compose(lua)?,
|
||||
b"Wrap" => super::Wrap::compose(lua)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)
|
||||
}
|
||||
|
||||
fn set(_: &Lua, _: &[u8], value: Value) -> mlua::Result<Value> { Ok(value) }
|
||||
|
||||
Composer::with_parent(get, set, p_get, p_set)
|
||||
}
|
||||
|
|
@ -35,15 +35,6 @@ impl Spatial for Fill {
|
|||
fn set_area(&mut self, area: Area) { self.area = area; }
|
||||
}
|
||||
|
||||
impl Widget for Fill {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
(&self).render(rect, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &Fill {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use mlua::{AnyUserData, ExternalError, IntoLua, Lua, MetaMethod, Table, UserData
|
|||
use ratatui::widgets::Widget;
|
||||
|
||||
use super::{Area, Span};
|
||||
use crate::{Style, elements::Spatial};
|
||||
use crate::{elements::Spatial, style::Style};
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Gauge {
|
||||
|
|
|
|||
|
|
@ -1,117 +0,0 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
|
||||
use parking_lot::Mutex;
|
||||
use ratatui::widgets::Widget;
|
||||
|
||||
use super::Area;
|
||||
use crate::{elements::Spatial, impl_area_method};
|
||||
|
||||
const EXPECTED: &str = "expected a table or a Input";
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Input {
|
||||
pub focus: bool,
|
||||
|
||||
inner: Arc<Mutex<yazi_widgets::input::Input>>,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Value> {
|
||||
let new = lua.create_function(|_, (_, input): (Table, Self)| Ok(input))?;
|
||||
|
||||
let input = lua.create_table()?;
|
||||
input.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?))?;
|
||||
input.into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Input> for Arc<Mutex<yazi_widgets::input::Input>> {
|
||||
fn from(input: &Input) -> Self { input.inner.clone() }
|
||||
}
|
||||
|
||||
impl TryFrom<&AnyUserData> for Input {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: &AnyUserData) -> Result<Self, Self::Error> {
|
||||
Ok(value.borrow::<Self>()?.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for Input {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(tb: Table) -> Result<Self, Self::Error> {
|
||||
let input = yazi_widgets::input::Input::new(yazi_widgets::input::InputOpt {
|
||||
cfg: yazi_config::popup::InputCfg {
|
||||
title: String::new(),
|
||||
value: tb.raw_get("value")?,
|
||||
cursor: None,
|
||||
obscure: false,
|
||||
position: Default::default(),
|
||||
realtime: false,
|
||||
completion: false,
|
||||
},
|
||||
cb: None,
|
||||
})?;
|
||||
|
||||
Ok(Self { inner: Arc::new(Mutex::new(input)), ..Default::default() })
|
||||
}
|
||||
}
|
||||
|
||||
impl Spatial for Input {
|
||||
fn area(&self) -> Area { self.inner.lock().pos.into() }
|
||||
|
||||
fn set_area(&mut self, area: Area) {
|
||||
self.inner.lock().repos(match area {
|
||||
Area::Rect(rect) => yazi_config::popup::Position {
|
||||
origin: yazi_config::popup::Origin::TopLeft,
|
||||
offset: yazi_config::popup::Offset {
|
||||
x: rect.x as i16,
|
||||
y: rect.y as i16,
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
},
|
||||
},
|
||||
Area::Pos(pos) => pos.into(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Input {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
(&self).render(rect, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &Input {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.inner.lock().render(rect, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Input {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(tb) => Self::try_from(tb),
|
||||
_ => Err(EXPECTED.into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Input {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
impl_area_method!(methods);
|
||||
|
||||
methods.add_function("focus", |lua, (ud, focus): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.focus = focus;
|
||||
ud.into_lua(lua)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -106,15 +106,6 @@ impl Spatial for Line {
|
|||
fn set_area(&mut self, area: Area) { self.area = area; }
|
||||
}
|
||||
|
||||
impl Widget for Line {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
(&self).render(rect, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &Line {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
|
|
|
|||
|
|
@ -37,15 +37,6 @@ impl Spatial for List {
|
|||
fn set_area(&mut self, area: Area) { self.area = area; }
|
||||
}
|
||||
|
||||
impl Widget for List {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
(&self).render(rect, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for &List {
|
||||
fn render(self, rect: ratatui::layout::Rect, buf: &mut ratatui::buffer::Buffer)
|
||||
where
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(align area bar border cell clear color constraint edge elements fill gauge input layout line list pad pos rect renderable renderables row span spatial table text wrap);
|
||||
yazi_macro::mod_flat!(align area bar border cell color constraint edge fill gauge layout line list pad pos rect row span spatial table text wrap);
|
||||
|
|
|
|||
|
|
@ -4,29 +4,28 @@ use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, Me
|
|||
use yazi_shim::strum::IntoStr;
|
||||
|
||||
use super::Pad;
|
||||
use crate::position::{Offset, Origin, Position};
|
||||
|
||||
const EXPECTED: &str = "expected a Pos";
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct Pos {
|
||||
inner: yazi_config::popup::Position,
|
||||
inner: Position,
|
||||
|
||||
pub(super) pad: Pad,
|
||||
}
|
||||
|
||||
impl Deref for Pos {
|
||||
type Target = yazi_config::popup::Position;
|
||||
type Target = Position;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<yazi_config::popup::Position> for Pos {
|
||||
fn from(value: yazi_config::popup::Position) -> Self {
|
||||
Self { inner: value, ..Default::default() }
|
||||
}
|
||||
impl From<Position> for Pos {
|
||||
fn from(value: Position) -> Self { Self { inner: value, ..Default::default() } }
|
||||
}
|
||||
|
||||
impl From<Pos> for yazi_config::popup::Position {
|
||||
impl From<Pos> for Position {
|
||||
fn from(value: Pos) -> Self { value.inner }
|
||||
}
|
||||
|
||||
|
|
@ -42,8 +41,6 @@ impl TryFrom<Table> for Pos {
|
|||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(t: Table) -> Result<Self, Self::Error> {
|
||||
use yazi_config::popup::{Offset, Origin, Position};
|
||||
|
||||
Ok(Self::from(Position {
|
||||
origin: Origin::from_str(&t.raw_get::<mlua::String>(1)?.to_str()?).into_lua_err()?,
|
||||
offset: Offset {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use mlua::{AnyUserData, IntoLua, Lua, MetaMethod, UserData, UserDataMethods, Val
|
|||
use ratatui::widgets::{StatefulWidget, Widget};
|
||||
|
||||
use super::{Area, Row};
|
||||
use crate::{Style, elements::{Constraint, Spatial}};
|
||||
use crate::{elements::{Constraint, Spatial}, style::Style};
|
||||
|
||||
// --- Table
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{any::TypeId, mem};
|
|||
use ansi_to_tui::IntoText;
|
||||
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, Table, UserData, UserDataMethods, Value};
|
||||
use ratatui::widgets::Widget;
|
||||
use yazi_shared::SStr;
|
||||
use yazi_shim::SStr;
|
||||
|
||||
use super::{Area, Line, Span, Wrap};
|
||||
use crate::{Error, elements::{Align, Spatial}};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{FromLua, IntoLua, Lua, Value};
|
||||
use yazi_config::preview::PreviewWrap;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct Wrap(pub(super) Option<ratatui::widgets::Wrap>);
|
||||
pub struct Wrap(pub Option<ratatui::widgets::Wrap>);
|
||||
|
||||
impl Deref for Wrap {
|
||||
type Target = Option<ratatui::widgets::Wrap>;
|
||||
|
|
@ -26,15 +25,6 @@ impl From<ratatui::widgets::Wrap> for Wrap {
|
|||
fn from(value: ratatui::widgets::Wrap) -> Self { Self(Some(value)) }
|
||||
}
|
||||
|
||||
impl From<PreviewWrap> for Wrap {
|
||||
fn from(value: PreviewWrap) -> Self {
|
||||
Self(match value {
|
||||
PreviewWrap::No => None,
|
||||
PreviewWrap::Yes => Some(ratatui::widgets::Wrap { trim: false }),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for Wrap {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
let Value::Integer(n) = value else {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ use std::{borrow::Cow, fmt::Display};
|
|||
|
||||
use mlua::{ExternalError, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, Value};
|
||||
use yazi_codegen::FromLuaOwned;
|
||||
use yazi_shared::SStr;
|
||||
use yazi_shim::SStr;
|
||||
|
||||
#[derive(FromLuaOwned)]
|
||||
pub enum Error {
|
||||
Io(std::io::Error),
|
||||
Fs(yazi_fs::error::Error),
|
||||
Fs(yazi_shim::fs::Error),
|
||||
Serde(serde_json::Error),
|
||||
Custom(SStr),
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ impl Error {
|
|||
|
||||
let fs = lua.create_function(|_, value: Value| {
|
||||
Ok(Self::Fs(match value {
|
||||
Value::Table(t) => yazi_fs::error::Error::custom(
|
||||
Value::Table(t) => yazi_shim::fs::Error::custom(
|
||||
&t.raw_get::<mlua::String>("kind")?.to_str()?,
|
||||
t.raw_get("code")?,
|
||||
&t.raw_get::<mlua::String>("message")?.to_str()?,
|
||||
|
|
@ -64,7 +64,7 @@ impl UserData for Error {
|
|||
});
|
||||
fields.add_field_method_get("kind", |_, me| {
|
||||
Ok(match me {
|
||||
Self::Io(e) => Some(yazi_fs::error::Error::from(e.kind()).kind_str()),
|
||||
Self::Io(e) => Some(yazi_shim::fs::Error::from(e.kind()).kind_str()),
|
||||
Self::Fs(e) => Some(e.kind_str()),
|
||||
_ => None,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use mlua::{FromLua, Lua, UserData, UserDataFields, Value};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::event::Cmd;
|
||||
|
||||
pub struct Action {
|
||||
inner: yazi_shared::event::Action,
|
||||
}
|
||||
|
||||
impl Deref for Action {
|
||||
type Target = yazi_shared::event::Action;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl DerefMut for Action {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
|
||||
}
|
||||
|
||||
impl From<Action> for yazi_shared::event::Action {
|
||||
fn from(value: Action) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl From<Action> for yazi_shared::event::Actions {
|
||||
fn from(value: Action) -> Self { Self::from(value.inner) }
|
||||
}
|
||||
|
||||
impl Action {
|
||||
pub fn new(inner: impl Into<yazi_shared::event::Action>) -> Self { Self { inner: inner.into() } }
|
||||
}
|
||||
|
||||
impl FromLua for Action {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
Ok(match value {
|
||||
Value::String(s) => Self { inner: s.to_str()?.parse()? },
|
||||
Value::UserData(ud) => ud.take()?,
|
||||
_ => Err(mlua::Error::FromLuaConversionError {
|
||||
from: value.type_name(),
|
||||
to: "Action".to_owned(),
|
||||
message: Some("expected a string or an Action".to_string()),
|
||||
})?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Action {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("cmd", |_, me| Ok(Cmd::new(me.cmd.clone())));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
|
||||
|
||||
use crate::event::Action;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Actions {
|
||||
inner: yazi_shared::event::Actions,
|
||||
}
|
||||
|
||||
impl Deref for Actions {
|
||||
type Target = yazi_shared::event::Actions;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl DerefMut for Actions {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
|
||||
}
|
||||
|
||||
impl From<Actions> for yazi_shared::event::Actions {
|
||||
fn from(value: Actions) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl Actions {
|
||||
pub fn new(inner: yazi_shared::event::Actions) -> Self { Self { inner } }
|
||||
}
|
||||
|
||||
impl FromLua for Actions {
|
||||
fn from_lua(value: Value, lua: &Lua) -> mlua::Result<Self> {
|
||||
let inner = match value {
|
||||
Value::Table(t) => t
|
||||
.sequence_values::<Action>()
|
||||
.map(|a| a.map(Into::into))
|
||||
.collect::<mlua::Result<Vec<_>>>()?
|
||||
.into(),
|
||||
v @ Value::String(_) => Action::from_lua(v, lua)?.into(),
|
||||
_ => Err("expected a string or a table of actions".into_lua_err())?,
|
||||
};
|
||||
|
||||
Ok(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLua for Actions {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
lua.create_sequence_from(self.inner.into_iter().map(Action::new))?.into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
use std::{mem, ops::{Deref, DerefMut}};
|
||||
|
||||
use mlua::{UserData, UserDataFields};
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::Sendable;
|
||||
|
||||
pub struct Cmd {
|
||||
inner: yazi_shared::event::Cmd,
|
||||
}
|
||||
|
||||
impl Deref for Cmd {
|
||||
type Target = yazi_shared::event::Cmd;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl DerefMut for Cmd {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
|
||||
}
|
||||
|
||||
impl Cmd {
|
||||
pub fn new(inner: impl Into<yazi_shared::event::Cmd>) -> Self { Self { inner: inner.into() } }
|
||||
}
|
||||
|
||||
impl UserData for Cmd {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field_mut("name", |_, me| Ok(mem::take(&mut me.name)));
|
||||
|
||||
fields.add_cached_field_mut("args", |lua, me| {
|
||||
Sendable::args_to_table(lua, mem::take(&mut me.args))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
yazi_macro::mod_flat!(action actions cmd);
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, ExternalError, FromLua, Lua, ObjectLike, Table, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
|
||||
|
||||
use crate::{Cha, Url, impl_file_fields, impl_file_methods};
|
||||
|
||||
pub type FileRef = UserDataRef<File>;
|
||||
|
||||
const EXPECTED: &str = "expected a table, File, or fs::File";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct File {
|
||||
pub(crate) inner: yazi_fs::File,
|
||||
}
|
||||
|
||||
impl Deref for File {
|
||||
type Target = yazi_fs::File;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<File> for yazi_fs::File {
|
||||
fn from(value: File) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn new(inner: impl Into<yazi_fs::File>) -> Self { Self { inner: inner.into() } }
|
||||
|
||||
pub fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.globals().raw_set("File", lua.create_function(|_, file: Self| Ok(file))?)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Table> for File {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
Ok(Self::new(yazi_fs::File {
|
||||
url: value.raw_get::<Url>("url")?.into(),
|
||||
cha: *value.raw_get::<Cha>("cha")?,
|
||||
..Default::default()
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AnyUserData> for File {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: AnyUserData) -> Result<Self, Self::Error> {
|
||||
Ok(if let Ok(me) = value.take::<Self>() { me } else { value.get("bare")? })
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for File {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(tbl) => Self::try_from(tbl),
|
||||
Value::UserData(ud) => Self::try_from(ud),
|
||||
_ => Err(EXPECTED.into_lua_err())?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for File {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
impl_file_fields!(fields);
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
impl_file_methods!(methods);
|
||||
|
||||
methods.add_method("icon", |_, me, ()| {
|
||||
use crate::Icon;
|
||||
// TODO: use a cache
|
||||
Ok(yazi_config::THEME.icon.matches(me, false).map(Icon::from))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{IntoLua, Lua, Value};
|
||||
|
||||
use crate::Style;
|
||||
|
||||
pub struct Icon {
|
||||
inner: yazi_config::Icon,
|
||||
}
|
||||
|
||||
impl Deref for Icon {
|
||||
type Target = yazi_config::Icon;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<yazi_config::Icon> for Icon {
|
||||
fn from(inner: yazi_config::Icon) -> Self { Self { inner } }
|
||||
}
|
||||
|
||||
impl IntoLua for Icon {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
lua
|
||||
.create_table_from([
|
||||
("text", self.inner.text.into_lua(lua)?),
|
||||
("style", Style::from(self.inner.style).into_lua(lua)?),
|
||||
])?
|
||||
.into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,43 @@
|
|||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use image::{ImageDecoder, ImageError};
|
||||
use mlua::{MetaMethod, UserData, UserDataFields, UserDataMethods};
|
||||
|
||||
pub struct ImageInfo(yazi_adapter::ImageInfo);
|
||||
|
||||
impl Deref for ImageInfo {
|
||||
type Target = yazi_adapter::ImageInfo;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
// --- ImageInfo
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ImageInfo {
|
||||
pub format: image::ImageFormat,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub color: image::ColorType,
|
||||
pub orientation: Option<image::metadata::Orientation>,
|
||||
}
|
||||
|
||||
impl From<yazi_adapter::ImageInfo> for ImageInfo {
|
||||
fn from(value: yazi_adapter::ImageInfo) -> Self { Self(value) }
|
||||
impl ImageInfo {
|
||||
pub async fn new(path: PathBuf) -> image::ImageResult<Self> {
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let reader = image::ImageReader::open(path)?.with_guessed_format()?;
|
||||
|
||||
let Some(format) = reader.format() else {
|
||||
return Err(ImageError::IoError(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
"unknown image format",
|
||||
)));
|
||||
};
|
||||
|
||||
let mut decoder = reader.into_decoder()?;
|
||||
let (width, height) = decoder.dimensions();
|
||||
Ok(Self {
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
color: decoder.color_type(),
|
||||
orientation: decoder.orientation().ok(),
|
||||
})
|
||||
})
|
||||
.await
|
||||
.map_err(|e| ImageError::IoError(e.into()))?
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for ImageInfo {
|
||||
|
|
@ -25,12 +51,12 @@ impl UserData for ImageInfo {
|
|||
}
|
||||
|
||||
// --- ImageFormat
|
||||
struct ImageFormat(yazi_adapter::ImageFormat);
|
||||
struct ImageFormat(image::ImageFormat);
|
||||
|
||||
impl UserData for ImageFormat {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::ToString, |_, me, ()| {
|
||||
use yazi_adapter::ImageFormat as F;
|
||||
use image::ImageFormat as F;
|
||||
|
||||
Ok(match me.0 {
|
||||
F::Png => "PNG",
|
||||
|
|
@ -55,12 +81,12 @@ impl UserData for ImageFormat {
|
|||
}
|
||||
|
||||
// --- ImageColor
|
||||
struct ImageColor(yazi_adapter::ImageColor);
|
||||
struct ImageColor(image::ColorType);
|
||||
|
||||
impl UserData for ImageColor {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::ToString, |_, me, ()| {
|
||||
use yazi_adapter::ImageColor as C;
|
||||
use image::ColorType as C;
|
||||
|
||||
Ok(match me.0 {
|
||||
C::L8 => "L8",
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataFields, Value};
|
||||
use serde::Deserialize;
|
||||
use yazi_codegen::FromLuaOwned;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::{Id, Iter, event::Actions, keymap::Key};
|
||||
|
||||
#[derive(FromLuaOwned)]
|
||||
pub struct Chord {
|
||||
inner: yazi_config::keymap::ChordArc,
|
||||
}
|
||||
|
||||
impl Deref for Chord {
|
||||
type Target = yazi_config::keymap::ChordArc;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl From<&yazi_config::keymap::ChordArc> for Chord {
|
||||
fn from(value: &yazi_config::keymap::ChordArc) -> Self { Self { inner: value.clone() } }
|
||||
}
|
||||
|
||||
impl From<Chord> for yazi_config::keymap::ChordArc {
|
||||
fn from(value: Chord) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl Chord {
|
||||
pub fn new(inner: impl Into<yazi_config::keymap::ChordArc>) -> Self {
|
||||
Self { inner: inner.into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(Value, yazi_shared::Layer)> for Chord {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from((value, layer): (Value, yazi_shared::Layer)) -> Result<Self, Self::Error> {
|
||||
use yazi_config::keymap::Chord as C;
|
||||
use yazi_shared::Layer as L;
|
||||
|
||||
let de = mlua::serde::Deserializer::new(value);
|
||||
let inner = match layer {
|
||||
L::Null => C::<{ L::Null as u8 }>::deserialize(de)?.into(),
|
||||
L::App => C::<{ L::App as u8 }>::deserialize(de)?.into(),
|
||||
L::Mgr => C::<{ L::Mgr as u8 }>::deserialize(de)?.into(),
|
||||
L::Tasks => C::<{ L::Tasks as u8 }>::deserialize(de)?.into(),
|
||||
L::Spot => C::<{ L::Spot as u8 }>::deserialize(de)?.into(),
|
||||
L::Pick => C::<{ L::Pick as u8 }>::deserialize(de)?.into(),
|
||||
L::Input => C::<{ L::Input as u8 }>::deserialize(de)?.into(),
|
||||
L::Confirm => C::<{ L::Confirm as u8 }>::deserialize(de)?.into(),
|
||||
L::Help => C::<{ L::Help as u8 }>::deserialize(de)?.into(),
|
||||
L::Cmp => C::<{ L::Cmp as u8 }>::deserialize(de)?.into(),
|
||||
L::Which => C::<{ L::Which as u8 }>::deserialize(de)?.into(),
|
||||
L::Notify => C::<{ L::Notify as u8 }>::deserialize(de)?.into(),
|
||||
};
|
||||
|
||||
Ok(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Chord {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("id", |_, me| Ok(Id(me.inner.id)));
|
||||
|
||||
fields
|
||||
.add_cached_field("on", |lua, me| lua.create_sequence_from(me.on.iter().copied().map(Key)));
|
||||
|
||||
fields.add_cached_field("run", |_, me| Ok(Actions::new(me.run.clone())));
|
||||
|
||||
fields.add_cached_field("desc", |lua, me| lua.create_string(&me.desc));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Matcher
|
||||
pub struct ChordMatcher(pub(super) yazi_config::keymap::ChordMatcher);
|
||||
|
||||
impl TryFrom<Table> for ChordMatcher {
|
||||
type Error = mlua::Error;
|
||||
|
||||
fn try_from(value: Table) -> Result<Self, Self::Error> {
|
||||
let id: Id = value.raw_get("id").unwrap_or_default();
|
||||
|
||||
Ok(Self(yazi_config::keymap::ChordMatcher { id: id.0, ..Default::default() }))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for ChordMatcher {
|
||||
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
|
||||
match value {
|
||||
Value::Table(t) => t.try_into(),
|
||||
_ => Err("expected a table of ChordMatcher".into_lua_err()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- ChordIter
|
||||
pub struct ChordIter(pub(super) yazi_config::keymap::ChordIter);
|
||||
|
||||
impl ChordIter {
|
||||
pub fn new(inner: impl Into<yazi_config::keymap::ChordIter>) -> Self { Self(inner.into()) }
|
||||
}
|
||||
|
||||
impl IntoLua for ChordIter {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
||||
Iter::new(self.0.map(Chord::new), None).into_lua(lua)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{ExternalError, ExternalResult, MetaMethod, Table, UserData, UserDataMethods, Value};
|
||||
use yazi_shim::mlua::DeserializeOverLua;
|
||||
|
||||
use super::{Chord, ChordMatcher};
|
||||
use crate::{event::Actions, keymap::ChordIter};
|
||||
|
||||
pub struct Chords {
|
||||
pub(super) inner: &'static yazi_config::keymap::Chords,
|
||||
pub(super) layer: yazi_shared::Layer,
|
||||
}
|
||||
|
||||
impl Deref for Chords {
|
||||
type Target = yazi_config::keymap::Chords;
|
||||
|
||||
fn deref(&self) -> &Self::Target { self.inner }
|
||||
}
|
||||
|
||||
impl UserData for Chords {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("match", |_, me, matcher: Option<ChordMatcher>| {
|
||||
Ok(match matcher {
|
||||
Some(matcher) => ChordIter::new(yazi_config::keymap::ChordIter {
|
||||
chords: me.as_erased(),
|
||||
matcher: matcher.0,
|
||||
..Default::default()
|
||||
}),
|
||||
None => ChordIter::new(&*me.inner),
|
||||
})
|
||||
});
|
||||
|
||||
methods.add_method("insert", |_, me, (index, value): (isize, Value)| {
|
||||
let index = match index {
|
||||
1.. => index - 1,
|
||||
0 => return Err("index must be 1-based or negative".into_lua_err()),
|
||||
_ => index,
|
||||
};
|
||||
|
||||
let chord = Chord::try_from((value, me.layer))?;
|
||||
me.insert(index, chord.clone()).into_lua_err()?;
|
||||
|
||||
Ok(chord)
|
||||
});
|
||||
|
||||
methods.add_method("remove", |_, me, matcher: ChordMatcher| {
|
||||
me.remove(matcher.0);
|
||||
Ok(())
|
||||
});
|
||||
|
||||
methods.add_method("update", |_, me, (matcher, table): (ChordMatcher, Table)| {
|
||||
let mut run: Option<Actions> = table.raw_get("run")?;
|
||||
if let Some(run) = &mut run {
|
||||
table.raw_remove("run")?;
|
||||
run.set(me.layer, yazi_shared::Source::Key);
|
||||
}
|
||||
|
||||
me.update(matcher.0, |mut chord| {
|
||||
chord = chord.deserialize_over_lua(&table)?;
|
||||
if let Some(run) = &run {
|
||||
chord.run = run.clone().into();
|
||||
}
|
||||
Ok(chord)
|
||||
})
|
||||
});
|
||||
|
||||
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.load().len()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, Value};
|
||||
|
||||
use crate::SER_OPT;
|
||||
|
||||
#[derive(Clone, Copy, Default, FromLua)]
|
||||
pub struct Key(pub yazi_config::keymap::Key);
|
||||
|
||||
impl Deref for Key {
|
||||
type Target = yazi_config::keymap::Key;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl IntoLua for Key {
|
||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { lua.to_value_with(&self.0, SER_OPT) }
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
yazi_macro::mod_flat!(chord chords key section);
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use anyhow::bail;
|
||||
use mlua::{UserData, UserDataFields};
|
||||
use yazi_config::KEYMAP;
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
use crate::keymap::Chords;
|
||||
|
||||
pub struct KeymapSection {
|
||||
inner: &'static yazi_config::keymap::KeymapSection,
|
||||
layer: yazi_shared::Layer,
|
||||
}
|
||||
|
||||
impl Deref for KeymapSection {
|
||||
type Target = yazi_config::keymap::KeymapSection;
|
||||
|
||||
fn deref(&self) -> &Self::Target { self.inner }
|
||||
}
|
||||
|
||||
impl TryFrom<yazi_shared::Layer> for KeymapSection {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(layer: yazi_shared::Layer) -> Result<Self, Self::Error> {
|
||||
use yazi_shared::Layer as L;
|
||||
|
||||
let inner = match layer {
|
||||
L::Null | L::App => bail!("invalid layer"),
|
||||
L::Mgr => KEYMAP.mgr.as_erased(),
|
||||
L::Tasks => KEYMAP.tasks.as_erased(),
|
||||
L::Spot => KEYMAP.spot.as_erased(),
|
||||
L::Pick => KEYMAP.pick.as_erased(),
|
||||
L::Input => KEYMAP.input.as_erased(),
|
||||
L::Confirm => KEYMAP.confirm.as_erased(),
|
||||
L::Help => KEYMAP.help.as_erased(),
|
||||
L::Cmp => KEYMAP.cmp.as_erased(),
|
||||
L::Which => bail!("invalid layer"),
|
||||
L::Notify => bail!("invalid layer"),
|
||||
};
|
||||
|
||||
Ok(Self { inner, layer })
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for KeymapSection {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_cached_field("rules", |_, me| Ok(Chords { inner: me.inner, layer: me.layer }));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
use mlua::{MetaMethod, UserData, UserDataMethods};
|
||||
use yazi_shim::strum::IntoStr;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Layer(yazi_shared::Layer);
|
||||
|
||||
impl From<yazi_shared::Layer> for Layer {
|
||||
fn from(event: yazi_shared::Layer) -> Self { Self(event) }
|
||||
}
|
||||
|
||||
impl UserData for Layer {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(MetaMethod::ToString, |_, me, ()| Ok(me.0.into_str()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
mod macros;
|
||||
|
||||
yazi_macro::mod_pub!(config elements event keymap process theme);
|
||||
yazi_macro::mod_pub!(elements position process style);
|
||||
|
||||
yazi_macro::mod_flat!(access calculator cha chan composer dnd error fd file handle icon id image input iter layer mouse path permit range runtime scheme selector sendable stage style tty url utils);
|
||||
yazi_macro::mod_flat!(chan composer error handle image iter permit range runtime);
|
||||
|
|
|
|||
|
|
@ -50,8 +50,7 @@ macro_rules! impl_area_method {
|
|||
"area",
|
||||
|lua, (ud, area): (mlua::AnyUserData, Option<mlua::AnyUserData>)| {
|
||||
use mlua::IntoLua;
|
||||
|
||||
use crate::elements::Spatial;
|
||||
use $crate::elements::Spatial;
|
||||
|
||||
if let Some(v) = area {
|
||||
ud.borrow_mut::<Self>()?.set_area((&v).try_into()?);
|
||||
|
|
@ -67,7 +66,7 @@ macro_rules! impl_area_method {
|
|||
#[macro_export]
|
||||
macro_rules! impl_style_method {
|
||||
($methods:ident, $($field:tt).+) => {
|
||||
$methods.add_function("style", |_, (ud, style): (mlua::AnyUserData, $crate::Style)| {
|
||||
$methods.add_function("style", |_, (ud, style): (mlua::AnyUserData, $crate::style::Style)| {
|
||||
ud.borrow_mut::<Self>()?.$($field).+ = style.0;
|
||||
Ok(ud)
|
||||
});
|
||||
|
|
@ -208,21 +207,22 @@ macro_rules! impl_file_fields {
|
|||
($fields:ident) => {
|
||||
use yazi_shim::mlua::UserDataFieldsExt;
|
||||
|
||||
$fields.add_cached_field("cha", |_, me| Ok($crate::Cha(me.cha)));
|
||||
$fields.add_cached_field("url", |_, me| Ok($crate::Url::new(me.url_owned())));
|
||||
$fields.add_cached_field("link_to", |_, me| Ok(me.link_to.as_ref().map($crate::Path::new)));
|
||||
$fields.add_cached_field("cha", |_, me| Ok(me.cha));
|
||||
$fields.add_cached_field("url", |_, me| Ok(me.url_owned()));
|
||||
$fields.add_cached_field("link_to", |_, me| Ok(me.link_to.clone()));
|
||||
|
||||
$fields.add_cached_field("name", |lua, me| {
|
||||
me.name().map(|s| lua.create_string(s.encoded_bytes())).transpose()
|
||||
});
|
||||
$fields.add_cached_field("path", |_, me| {
|
||||
use yazi_fs::FsUrl;
|
||||
use yazi_shared::url::AsUrl;
|
||||
Ok($crate::Path::new(me.url.as_url().unified_path()))
|
||||
use yazi_shared::{path::PathBufDyn, url::AsUrl};
|
||||
Ok(PathBufDyn::from(me.url.as_url().unified_path()))
|
||||
});
|
||||
$fields.add_cached_field("cache", |_, me| {
|
||||
use yazi_fs::FsUrl;
|
||||
Ok(me.url.cache().map($crate::Path::new))
|
||||
use yazi_shared::path::PathBufDyn;
|
||||
Ok(me.url.cache().map(PathBufDyn::from))
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{UserData, UserDataFields};
|
||||
use yazi_term::event::{MouseButton, MouseEventKind};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MouseEvent(yazi_term::event::MouseEvent);
|
||||
|
||||
impl Deref for MouseEvent {
|
||||
type Target = yazi_term::event::MouseEvent;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl From<yazi_term::event::MouseEvent> for MouseEvent {
|
||||
fn from(event: yazi_term::event::MouseEvent) -> Self { Self(event) }
|
||||
}
|
||||
|
||||
impl UserData for MouseEvent {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field("type", "legacy");
|
||||
fields.add_field_method_get("x", |_, me| Ok(me.column));
|
||||
fields.add_field_method_get("y", |_, me| Ok(me.row));
|
||||
fields.add_field_method_get("is_left", |_, me| {
|
||||
use MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Left))
|
||||
});
|
||||
fields.add_field_method_get("is_right", |_, me| {
|
||||
use MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Right))
|
||||
});
|
||||
fields.add_field_method_get("is_middle", |_, me| {
|
||||
use MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Middle))
|
||||
});
|
||||
}
|
||||
}
|
||||
1
yazi-binding/src/position/mod.rs
Normal file
1
yazi-binding/src/position/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
yazi_macro::mod_flat!(offset origin position);
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use ratatui::{layout::Rect, widgets::Padding};
|
||||
use yazi_term::Dimension;
|
||||
|
||||
use super::{Offset, Origin};
|
||||
|
||||
|
|
@ -24,7 +23,7 @@ impl DerefMut for Position {
|
|||
impl Position {
|
||||
pub const fn new(origin: Origin, offset: Offset) -> Self { Self { origin, offset } }
|
||||
|
||||
pub fn rect(&self, Dimension { cols, rows, .. }: Dimension) -> Rect {
|
||||
pub fn rect(&self, (cols, rows): (u16, u16)) -> Rect {
|
||||
use Origin::*;
|
||||
let Offset { x, y, width, height } = self.offset;
|
||||
|
||||
|
|
@ -54,7 +53,7 @@ impl Position {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn sticky(Dimension { cols, rows, .. }: Dimension, base: Rect, offset: Offset) -> Rect {
|
||||
pub fn sticky((cols, rows): (u16, u16), base: Rect, offset: Offset) -> Rect {
|
||||
let Offset { x, y, width, height } = offset;
|
||||
|
||||
let above =
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue