feat: key-* DDS events to allow canceling user key commands (#3005)

This commit is contained in:
三咲雅 misaki masa 2025-07-20 14:11:57 +08:00 committed by GitHub
parent c28d2e8180
commit 74bd98031e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
148 changed files with 893 additions and 465 deletions

29
Cargo.lock generated
View file

@ -352,9 +352,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.29" version = "1.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc", "libc",
@ -460,9 +460,9 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]] [[package]]
name = "clipboard-win" name = "clipboard-win"
version = "5.4.0" version = "5.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
dependencies = [ dependencies = [
"error-code", "error-code",
] ]
@ -1193,9 +1193,9 @@ dependencies = [
[[package]] [[package]]
name = "instability" name = "instability"
version = "0.3.7" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d" checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a"
dependencies = [ dependencies = [
"darling", "darling",
"indoc", "indoc",
@ -1335,9 +1335,9 @@ dependencies = [
[[package]] [[package]]
name = "libredox" name = "libredox"
version = "0.1.4" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.9.1",
"libc", "libc",
@ -2344,9 +2344,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.140" version = "1.0.141"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -3489,13 +3489,17 @@ version = "25.6.11"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"crossterm 0.29.0", "crossterm 0.29.0",
"foldhash",
"futures", "futures",
"indexmap",
"libc", "libc",
"mlua",
"paste", "paste",
"scopeguard", "scopeguard",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
"tracing", "tracing",
"yazi-binding",
"yazi-boot", "yazi-boot",
"yazi-config", "yazi-config",
"yazi-core", "yazi-core",
@ -3696,9 +3700,7 @@ dependencies = [
"better-panic", "better-panic",
"crossterm 0.29.0", "crossterm 0.29.0",
"fdlimit", "fdlimit",
"foldhash",
"futures", "futures",
"indexmap",
"libc", "libc",
"mlua", "mlua",
"paste", "paste",
@ -3829,8 +3831,6 @@ name = "yazi-proxy"
version = "25.6.11" version = "25.6.11"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"mlua",
"serde",
"tokio", "tokio",
"yazi-config", "yazi-config",
"yazi-macro", "yazi-macro",
@ -3868,7 +3868,6 @@ name = "yazi-shared"
version = "25.6.11" version = "25.6.11"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.9.1",
"crossterm 0.29.0", "crossterm 0.29.0",
"foldhash", "foldhash",
"futures", "futures",

View file

@ -43,7 +43,7 @@ ratatui = { version = "0.29.0", features = [ "unstable-rendered-line
regex = "1.11.1" regex = "1.11.1"
scopeguard = "1.2.0" scopeguard = "1.2.0"
serde = { version = "1.0.219", features = [ "derive" ] } serde = { version = "1.0.219", features = [ "derive" ] }
serde_json = "1.0.140" serde_json = "1.0.141"
syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] } syntect = { version = "5.2.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
tokio = { version = "1.46.1", features = [ "full" ] } tokio = { version = "1.46.1", features = [ "full" ] }
tokio-stream = "0.1.17" tokio-stream = "0.1.17"

View file

@ -1 +1 @@
{"version":"0.2","language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg"]} {"words":["Punct","KEYMAP","splitn","crossterm","YAZI","peekable","ratatui","syntect","pbpaste","pbcopy","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp","Konsole","Überzug","pkgs","pdftoppm","poppler","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable","natsort","backstack","luajit","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","nushell","msvc","aarch","linemode","sxyazi","rsplit","ZELLIJ","bitflags","bitflags","USERPROFILE","Neovim","vergen","gitcl","Renderable","preloaders","prec","Upserting","prio","Ghostty","Catmull","Lanczos","cmds","unyank","scrolloff","headsup","unsub","uzers","scopeguard","SPDLOG","globset","filetime","magick","magick","prefetcher","Prework","prefetchers","PREWORKERS","conds","translit","rxvt","Urxvt","realpath","realname","REPARSE","hardlink","hardlinking","nlink","nlink","linemodes","SIGSTOP","sevenzip","rsplitn","replacen","DECSET","DECRQM","repeek","cwds","tcsi","Hyprland","Wayfire","SWAYSOCK","btime","nsec","codegen","gethostname","fchmod","fdfind","Rustc","rustc","ffprobe","vframes","luma","obase","outln","errln","tmtheme","twox","cfgs","fstype","objc","rdev","runloop","exfat","rclone","DECRQSS","DECSCUSR","libvterm","Uninit","lockin","rposition","resvg","foldhash"],"version":"0.2","flagWords":[],"language":"en"}

View file

@ -8,7 +8,12 @@ description = "Yazi actor model"
homepage = "https://yazi-rs.github.io" homepage = "https://yazi-rs.github.io"
repository = "https://github.com/sxyazi/yazi" repository = "https://github.com/sxyazi/yazi"
[features]
default = [ "vendored-lua" ]
vendored-lua = [ "mlua/vendored" ]
[dependencies] [dependencies]
yazi-binding = { path = "../yazi-binding", version = "25.6.11" }
yazi-boot = { path = "../yazi-boot", version = "25.6.11" } yazi-boot = { path = "../yazi-boot", version = "25.6.11" }
yazi-config = { path = "../yazi-config", version = "25.6.11" } yazi-config = { path = "../yazi-config", version = "25.6.11" }
yazi-core = { path = "../yazi-core", version = "25.6.11" } yazi-core = { path = "../yazi-core", version = "25.6.11" }
@ -25,7 +30,10 @@ yazi-widgets = { path = "../yazi-widgets", version = "25.6.11" }
# External dependencies # External dependencies
anyhow = { workspace = true } anyhow = { workspace = true }
crossterm = { workspace = true } crossterm = { workspace = true }
foldhash = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
indexmap = { workspace = true }
mlua = { workspace = true }
paste = { workspace = true } paste = { workspace = true }
scopeguard = { workspace = true } scopeguard = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }

View file

@ -9,4 +9,6 @@ pub trait Actor {
const NAME: &str; const NAME: &str;
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data>; fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data>;
fn hook(_cx: &Ctx, _opt: &Self::Options) -> Option<&'static str> { None }
} }

View file

@ -3,11 +3,13 @@ use std::ops::{Deref, DerefMut};
use anyhow::{Result, anyhow}; use anyhow::{Result, anyhow};
use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}, tasks::Tasks}; use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}, tasks::Tasks};
use yazi_fs::File; use yazi_fs::File;
use yazi_shared::{event::Cmd, url::Url}; use yazi_shared::{Source, event::Cmd, url::Url};
pub struct Ctx<'a> { pub struct Ctx<'a> {
pub core: &'a mut Core, pub core: &'a mut Core,
pub tab: usize, pub tab: usize,
pub level: usize,
pub source: Source,
} }
impl Deref for Ctx<'_> { impl Deref for Ctx<'_> {
@ -36,15 +38,23 @@ impl<'a> Ctx<'a> {
core.mgr.tabs.cursor core.mgr.tabs.cursor
}; };
Ok(Self { core, tab }) Ok(Self { core, tab, level: 0, source: cmd.source })
}
#[inline]
pub fn renew<'b>(cx: &'a mut Ctx<'b>) -> Ctx<'a> {
let tab = cx.core.mgr.tabs.cursor;
Self { core: cx.core, tab, level: cx.level, source: cx.source }
} }
#[inline] #[inline]
pub fn active(core: &'a mut Core) -> Self { pub fn active(core: &'a mut Core) -> Self {
let tab = core.mgr.tabs.cursor; let tab = core.mgr.tabs.cursor;
Self { core, tab } Self { core, tab, level: 0, source: Source::Unknown }
} }
}
impl<'a> Ctx<'a> {
#[inline] #[inline]
pub fn tabs(&self) -> &Tabs { &self.mgr.tabs } pub fn tabs(&self) -> &Tabs { &self.mgr.tabs }
@ -80,4 +90,15 @@ impl<'a> Ctx<'a> {
#[inline] #[inline]
pub fn tasks(&self) -> &Tasks { &self.tasks } pub fn tasks(&self) -> &Tasks { &self.tasks }
#[inline]
pub fn source(&self) -> Source {
use Source::*;
match self.source {
Key if self.level != 1 => Ind,
Emit if self.level != 1 => EmitInd,
Relay if self.level != 1 => RelayInd,
s => s,
}
}
} }

View file

@ -0,0 +1 @@
yazi_macro::mod_flat!(preflight);

View file

@ -0,0 +1,48 @@
use std::marker::PhantomData;
use anyhow::Result;
use mlua::{IntoLua, Value};
use tracing::error;
use yazi_binding::runtime_mut;
use yazi_dds::{LOCAL, body::Body};
use yazi_macro::succ;
use yazi_plugin::LUA;
use yazi_shared::event::Data;
use crate::{Actor, Ctx, lives::Lives};
pub struct Preflight<'a> {
_lifetime: PhantomData<&'a ()>,
}
impl<'a> Actor for Preflight<'a> {
type Options = (&'static str, Body<'a>);
const NAME: &'static str = "preflight";
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
let kind = opt.0;
let Some(handlers) = LOCAL.read().get(kind).filter(|&m| !m.is_empty()).cloned() else {
succ!(false)
};
succ!(Lives::scope(cx.core, || {
let body = opt.1.into_lua(&LUA)?;
for (id, cb) in handlers {
runtime_mut!(LUA)?.push(&id);
let result = cb.call::<Value>(body.clone());
runtime_mut!(LUA)?.pop();
match result {
Ok(Value::Boolean(true)) => return Ok(true),
Ok(Value::Nil | Value::Boolean(false)) => {}
Ok(v) => {
error!("Unexpected return type from `{kind}` event handler in `{id}` plugin: {v:?}")
}
Err(e) => error!("Failed to run `{kind}` event handler in `{id}` plugin: {e}"),
}
}
Ok(false)
})?)
}
}

View file

@ -2,6 +2,6 @@
extern crate self as yazi_actor; extern crate self as yazi_actor;
yazi_macro::mod_pub!(cmp confirm help input mgr pick spot tasks which); yazi_macro::mod_pub!(cmp confirm core help input lives mgr pick spot tasks which);
yazi_macro::mod_flat!(actor context); yazi_macro::mod_flat!(actor context);

View file

@ -13,13 +13,10 @@ static TO_DESTROY: RoCell<RefCell<Vec<AnyUserData>>> = RoCell::new_const(RefCell
pub(super) static FILE_CACHE: RoCell<RefCell<HashMap<PtrCell<yazi_fs::File>, AnyUserData>>> = pub(super) static FILE_CACHE: RoCell<RefCell<HashMap<PtrCell<yazi_fs::File>, AnyUserData>>> =
RoCell::new(); RoCell::new();
pub(crate) struct Lives; pub struct Lives;
impl Lives { impl Lives {
pub(crate) fn scope<T>( pub fn scope<T>(core: &yazi_core::Core, f: impl FnOnce() -> mlua::Result<T>) -> mlua::Result<T> {
core: &yazi_core::Core,
f: impl FnOnce() -> mlua::Result<T>,
) -> mlua::Result<T> {
FILE_CACHE.init(Default::default()); FILE_CACHE.init(Default::default());
defer! { FILE_CACHE.drop(); } defer! { FILE_CACHE.drop(); }

View file

@ -59,6 +59,10 @@ impl Actor for Quit {
}); });
succ!(); succ!();
} }
fn hook(cx: &Ctx, _opt: &Self::Options) -> Option<&'static str> {
Some("key-quit").filter(|_| cx.source().is_key())
}
} }
impl Quit { impl Quit {

View file

@ -6,7 +6,7 @@ use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_fs::{FilesOp, cha::Cha}; use yazi_fs::{FilesOp, cha::Cha};
use yazi_macro::{act, succ}; use yazi_macro::{act, succ};
use yazi_parser::mgr::{SearchOpt, SearchOptVia}; use yazi_parser::{VoidOpt, mgr::{SearchOpt, SearchOptVia}};
use yazi_plugin::external; use yazi_plugin::external;
use yazi_proxy::{InputProxy, MgrProxy}; use yazi_proxy::{InputProxy, MgrProxy};
use yazi_shared::event::Data; use yazi_shared::event::Data;
@ -97,7 +97,7 @@ impl Actor for SearchDo {
pub struct SearchStop; pub struct SearchStop;
impl Actor for SearchStop { impl Actor for SearchStop {
type Options = (); type Options = VoidOpt;
const NAME: &str = "search_stop"; const NAME: &str = "search_stop";

View file

@ -1,26 +1,24 @@
use std::str::FromStr;
use anyhow::Result; use anyhow::Result;
use yazi_fs::SortBy;
use yazi_macro::{act, succ}; use yazi_macro::{act, succ};
use yazi_shared::event::{CmdCow, Data}; use yazi_parser::mgr::SortOpt;
use yazi_shared::event::Data;
use crate::{Actor, Ctx}; use crate::{Actor, Ctx};
pub struct Sort; pub struct Sort;
impl Actor for Sort { impl Actor for Sort {
type Options = CmdCow; type Options = SortOpt;
const NAME: &str = "sort"; const NAME: &str = "sort";
fn act(cx: &mut Ctx, c: Self::Options) -> Result<Data> { fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
let mut new = cx.tab().pref.clone(); let mut new = cx.tab().pref.clone();
new.sort_by = c.first_str().and_then(|s| SortBy::from_str(s).ok()).unwrap_or(new.sort_by); new.sort_by = opt.by.unwrap_or(new.sort_by);
new.sort_reverse = c.maybe_bool("reverse").unwrap_or(new.sort_reverse); new.sort_reverse = opt.reverse.unwrap_or(new.sort_reverse);
new.sort_dir_first = c.maybe_bool("dir-first").unwrap_or(new.sort_dir_first); new.sort_dir_first = opt.dir_first.unwrap_or(new.sort_dir_first);
new.sort_sensitive = c.maybe_bool("sensitive").unwrap_or(new.sort_sensitive); new.sort_sensitive = opt.sensitive.unwrap_or(new.sort_sensitive);
new.sort_translit = c.maybe_bool("translit").unwrap_or(new.sort_translit); new.sort_translit = opt.translit.unwrap_or(new.sort_translit);
if new == cx.tab().pref { if new == cx.tab().pref {
succ!(); succ!();

View file

@ -27,7 +27,7 @@ impl Actor for TabClose {
tabs.set_idx(usize::min(tabs.cursor + 1, tabs.len() - 1)); tabs.set_idx(usize::min(tabs.cursor + 1, tabs.len() - 1));
} }
let cx = &mut Ctx::active(cx.core); let cx = &mut Ctx::renew(cx);
act!(mgr:refresh, cx)?; act!(mgr:refresh, cx)?;
act!(mgr:peek, cx, true)?; act!(mgr:peek, cx, true)?;

View file

@ -41,7 +41,7 @@ impl Actor for TabCreate {
tabs.items.insert(tabs.cursor + 1, tab); tabs.items.insert(tabs.cursor + 1, tab);
tabs.set_idx(tabs.cursor + 1); tabs.set_idx(tabs.cursor + 1);
let cx = &mut Ctx::active(cx.core); let cx = &mut Ctx::renew(cx);
if cd { if cd {
act!(mgr:cd, cx, (url, CdSource::Tab))?; act!(mgr:cd, cx, (url, CdSource::Tab))?;
} else { } else {

View file

@ -23,7 +23,7 @@ impl Actor for TabSwap {
tabs.items.swap(tabs.cursor, new); tabs.items.swap(tabs.cursor, new);
tabs.set_idx(new); tabs.set_idx(new);
let cx = &mut Ctx::active(cx.core); let cx = &mut Ctx::renew(cx);
act!(mgr:refresh, cx)?; act!(mgr:refresh, cx)?;
act!(mgr:peek, cx, true)?; act!(mgr:peek, cx, true)?;

View file

@ -25,7 +25,7 @@ impl Actor for TabSwitch {
} }
tabs.set_idx(idx); tabs.set_idx(idx);
let cx = &mut Ctx::active(cx.core); let cx = &mut Ctx::renew(cx);
act!(mgr:refresh, cx)?; act!(mgr:refresh, cx)?;
act!(mgr:peek, cx, true)?; act!(mgr:peek, cx, true)?;

View file

@ -7,7 +7,7 @@ use yazi_shared::env_exists;
use crate::{Emulator, SHOWN, TMUX, drivers}; use crate::{Emulator, SHOWN, TMUX, drivers};
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Adapter { pub enum Adapter {
Kgp, Kgp,
KgpOld, KgpOld,

View file

@ -3,7 +3,7 @@ use yazi_shared::env_exists;
use crate::Mux; use crate::Mux;
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Brand { pub enum Brand {
Kitty, Kitty,
Konsole, Konsole,

View file

@ -1,6 +1,6 @@
use crate::Adapter; use crate::Adapter;
#[derive(Debug, Clone, Copy)] #[derive(Clone, Copy, Debug)]
pub struct Unknown { pub struct Unknown {
pub kgp: bool, pub kgp: bool,
pub sixel: bool, pub sixel: bool,

View file

@ -8,6 +8,10 @@ description = "Yazi Lua bindings"
homepage = "https://yazi-rs.github.io" homepage = "https://yazi-rs.github.io"
repository = "https://github.com/sxyazi/yazi" repository = "https://github.com/sxyazi/yazi"
[features]
default = [ "vendored-lua" ]
vendored-lua = [ "mlua/vendored" ]
[dependencies] [dependencies]
yazi-adapter = { path = "../yazi-adapter", version = "25.6.11" } yazi-adapter = { path = "../yazi-adapter", version = "25.6.11" }
yazi-config = { path = "../yazi-config", version = "25.6.11" } yazi-config = { path = "../yazi-config", version = "25.6.11" }

View file

@ -4,4 +4,4 @@ mod macros;
yazi_macro::mod_pub!(elements); yazi_macro::mod_pub!(elements);
yazi_macro::mod_flat!(cha color composer error file icon id iter permit runtime source stage style url urn utils); yazi_macro::mod_flat!(cha color composer error file icon id iter permit runtime stage style url urn utils);

View file

@ -24,7 +24,7 @@ macro_rules! deprecate {
None => "`init.lua` config", None => "`init.lua` config",
}; };
yazi_macro::emit!(Call( yazi_macro::emit!(Call(
yazi_shared::event::Cmd::new("app:deprecate").with("content", format!($tt, id)) yazi_macro::relay!(app:deprecate).with("content", format!($tt, id))
)); ));
} }
}}; }};

View file

@ -1,7 +0,0 @@
use mlua::{IntoLua, Lua, Value};
pub struct Source(pub yazi_shared::Source);
impl IntoLua for Source {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { self.0.bits().into_lua(lua) }
}

View file

@ -3,7 +3,7 @@ use std::{borrow::Cow, hash::{Hash, Hasher}, sync::OnceLock};
use anyhow::Result; use anyhow::Result;
use regex::Regex; use regex::Regex;
use serde::Deserialize; use serde::Deserialize;
use yazi_shared::{Layer, event::Cmd}; use yazi_shared::{Layer, Source, event::Cmd};
use super::Key; use super::Key;
@ -60,6 +60,7 @@ impl Chord {
impl Chord { impl Chord {
pub(super) fn reshape(mut self, layer: Layer) -> Result<Self> { pub(super) fn reshape(mut self, layer: Layer) -> Result<Self> {
for cmd in &mut self.run { for cmd in &mut self.run {
cmd.source = Source::Key;
if cmd.layer == Default::default() { if cmd.layer == Default::default() {
cmd.layer = layer; cmd.layer = layer;
} }

View file

@ -3,7 +3,7 @@ use std::{fmt::{Display, Write}, str::FromStr};
use anyhow::bail; use anyhow::bail;
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Key { pub struct Key {
pub code: KeyCode, pub code: KeyCode,
pub shift: bool, pub shift: bool,

View file

@ -1,6 +1,6 @@
use ratatui::layout::Rect; use ratatui::layout::Rect;
#[derive(Clone, Copy, Default, PartialEq, Eq)] #[derive(Clone, Copy, Default, Eq, PartialEq)]
pub struct Layout { pub struct Layout {
pub current: Rect, pub current: Rect,
pub preview: Rect, pub preview: Rect,

View file

@ -4,7 +4,7 @@ use crossterm::event::MouseEventKind;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
bitflags! { bitflags! {
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(try_from = "Vec<String>", into = "Vec<String>")] #[serde(try_from = "Vec<String>", into = "Vec<String>")]
pub struct MouseEvents: u8 { pub struct MouseEvents: u8 {
const CLICK = 0b00001; const CLICK = 0b00001;

View file

@ -1,7 +1,7 @@
use anyhow::bail; use anyhow::bail;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[serde(try_from = "[u16; 3]")] #[serde(try_from = "[u16; 3]")]
pub struct MgrRatio { pub struct MgrRatio {
pub parent: u16, pub parent: u16,

View file

@ -1,7 +1,7 @@
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use serde::Deserialize; use serde::Deserialize;
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct OpenerRule { pub struct OpenerRule {
pub run: String, pub run: String,
#[serde(default)] #[serde(default)]

View file

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub enum PreviewWrap { pub enum PreviewWrap {
No, No,

View file

@ -1,6 +1,6 @@
use serde::Deserialize; use serde::Deserialize;
#[derive(Default, Clone, Copy, Debug, Deserialize)] #[derive(Clone, Copy, Debug, Default, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub enum Priority { pub enum Priority {
Low = 0, Low = 0,

View file

@ -1,72 +0,0 @@
use anyhow::bail;
use crate::body::Body;
macro_rules! unsupported {
[ $( $layer:ident : $name:ident $(<$lt:lifetime>)? $(,)? )+ ] => {
$(
paste::paste! {
unsupported!(yazi_parser::$layer::[<$name:camel Opt>] $(<$lt>)?);
}
)+
};
[ $( $path:path $(,)? )+ ] => {
$(
impl TryFrom<&$path> for Body<'static> {
type Error = anyhow::Error;
fn try_from(_: &$path) -> Result<Self, Self::Error> {
bail!("unsupported");
}
}
)+
};
}
unsupported!(
mgr:cd
mgr:close
mgr:copy
mgr:create
mgr:escape
mgr:filter
mgr:find
mgr:find_arrow
mgr:find_do
mgr:forward
mgr:hardlink
mgr:hidden
mgr:linemode
mgr:link
mgr:open
mgr:open_do
mgr:paste
mgr:peek
mgr:remove
mgr:rename
mgr:reveal
mgr:search
mgr:seek
mgr:shell
mgr:spot
mgr:tab_close
mgr:tab_create
mgr:tab_switch
mgr:toggle
mgr:toggle_all
mgr:update_files
mgr:update_mimes
mgr:update_paged
mgr:update_peeked
mgr:update_spotted
mgr:update_tasks
mgr:update_yanked<'_>
mgr:visual_mode
mgr:yank
);
unsupported!(
yazi_parser::ArrowOpt
yazi_parser::VoidOpt
yazi_shared::event::CmdCow
);

View file

@ -1,36 +0,0 @@
use mlua::{IntoLua, Lua, Value};
use serde::{Deserialize, Serialize};
use yazi_parser::mgr::QuitOpt;
use yazi_shared::Source;
use crate::{body::Body, local_or_err};
#[derive(Debug, Serialize, Deserialize)]
pub struct BeforeQuitBody {
pub opts: QuitOpt,
pub source: Source,
}
impl IntoLua for BeforeQuitBody {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua
.create_table_from([
("opts", self.opts.into_lua(lua)?),
("source", yazi_binding::Source(self.source).into_lua(lua)?),
])?
.into_lua(lua)
}
}
impl TryFrom<&QuitOpt> for Body<'static> {
type Error = anyhow::Error;
fn try_from(value: &QuitOpt) -> Result<Self, Self::Error> {
local_or_err!("before-quit");
Ok(Body::BeforeQuit(BeforeQuitBody {
opts: value.clone(),
source: Source::default(), // FIXME
}))
}
}

View file

@ -1,13 +1,11 @@
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use mlua::{ExternalResult, IntoLua, Lua, Value}; use mlua::{ExternalResult, IntoLua, Lua, Value};
use serde::Serialize;
use yazi_shared::Id; use yazi_shared::Id;
use super::{BeforeQuitBody, BodyBulk, BodyBye, BodyCd, BodyCustom, BodyDelete, BodyHey, BodyHi, BodyHover, BodyLoad, BodyMount, BodyMove, BodyRename, BodyTab, BodyTrash, BodyYank}; use super::{BodyBulk, BodyBye, BodyCd, BodyCustom, BodyDelete, BodyHey, BodyHi, BodyHover, BodyLoad, BodyMount, BodyMove, BodyRename, BodyTab, BodyTrash, BodyYank};
use crate::Payload; use crate::Payload;
#[derive(Debug, Serialize)] #[derive(Debug)]
#[serde(untagged)]
pub enum Body<'a> { pub enum Body<'a> {
Hi(BodyHi<'a>), Hi(BodyHi<'a>),
Hey(BodyHey), Hey(BodyHey),
@ -23,8 +21,74 @@ pub enum Body<'a> {
Trash(BodyTrash<'a>), Trash(BodyTrash<'a>),
Delete(BodyDelete<'a>), Delete(BodyDelete<'a>),
Mount(BodyMount), Mount(BodyMount),
BeforeQuit(BeforeQuitBody),
Custom(BodyCustom), Custom(BodyCustom),
// Manager key events
KeyArrow(&'a yazi_parser::ArrowOpt),
KeyBack(&'a yazi_parser::VoidOpt),
KeyBulkRename(&'a yazi_parser::VoidOpt),
KeyCd(&'a yazi_parser::mgr::CdOpt),
KeyClose(&'a yazi_parser::mgr::CloseOpt),
KeyCopy(&'a yazi_parser::mgr::CopyOpt),
KeyCreate(&'a yazi_parser::mgr::CreateOpt),
KeyEnter(&'a yazi_parser::VoidOpt),
KeyEscape(&'a yazi_parser::mgr::EscapeOpt),
KeyEscapeFilter(&'a yazi_parser::VoidOpt),
KeyEscapeFind(&'a yazi_parser::VoidOpt),
KeyEscapeSearch(&'a yazi_parser::VoidOpt),
KeyEscapeSelect(&'a yazi_parser::VoidOpt),
KeyEscapeVisual(&'a yazi_parser::VoidOpt),
KeyFilter(&'a yazi_parser::mgr::FilterOpt),
KeyFilterDo(&'a yazi_parser::mgr::FilterOpt),
KeyFind(&'a yazi_parser::mgr::FindOpt),
KeyFindArrow(&'a yazi_parser::mgr::FindArrowOpt),
KeyFindDo(&'a yazi_parser::mgr::FindDoOpt),
KeyFollow(&'a yazi_parser::VoidOpt),
KeyForward(&'a yazi_parser::VoidOpt),
KeyHardlink(&'a yazi_parser::mgr::HardlinkOpt),
KeyHidden(&'a yazi_parser::mgr::HiddenOpt),
KeyHover(&'a yazi_parser::mgr::HoverOpt),
KeyHoverDo(&'a yazi_parser::mgr::HoverDoOpt),
KeyLeave(&'a yazi_parser::VoidOpt),
KeyLinemode(&'a yazi_parser::mgr::LinemodeOpt),
KeyLink(&'a yazi_parser::mgr::LinkOpt),
KeyOpen(&'a yazi_parser::mgr::OpenOpt),
KeyOpenDo(&'a yazi_parser::mgr::OpenDoOpt),
KeyPaste(&'a yazi_parser::mgr::PasteOpt),
KeyPeek(&'a yazi_parser::mgr::PeekOpt),
KeyQuit(&'a yazi_parser::mgr::QuitOpt),
KeyRefresh(&'a yazi_parser::VoidOpt),
KeyRemove(&'a yazi_parser::mgr::RemoveOpt),
KeyRemoveDo(&'a yazi_parser::mgr::RemoveOpt),
KeyRename(&'a yazi_parser::mgr::RenameOpt),
KeyReveal(&'a yazi_parser::mgr::RevealOpt),
KeySearch(&'a yazi_parser::mgr::SearchOpt),
KeySearchDo(&'a yazi_parser::mgr::SearchOpt),
KeySearchStop(&'a yazi_parser::VoidOpt),
KeySeek(&'a yazi_parser::mgr::SeekOpt),
KeyShell(&'a yazi_parser::mgr::ShellOpt),
KeySort(&'a yazi_parser::mgr::SortOpt),
KeySpot(&'a yazi_parser::mgr::SpotOpt),
KeySuspend(&'a yazi_parser::VoidOpt),
KeyTabClose(&'a yazi_parser::mgr::TabCloseOpt),
KeyTabCreate(&'a yazi_parser::mgr::TabCreateOpt),
KeyTabSwap(&'a yazi_parser::ArrowOpt),
KeyTabSwitch(&'a yazi_parser::mgr::TabSwitchOpt),
KeyToggle(&'a yazi_parser::mgr::ToggleOpt),
KeyToggleAll(&'a yazi_parser::mgr::ToggleAllOpt),
KeyUnyank(&'a yazi_parser::VoidOpt),
KeyUpdateFiles(&'a yazi_parser::mgr::UpdateFilesOpt),
KeyUpdateMimes(&'a yazi_parser::mgr::UpdateMimesOpt),
KeyUpdatePaged(&'a yazi_parser::mgr::UpdatePagedOpt),
KeyUpdatePeeked(&'a yazi_parser::mgr::UpdatePeekedOpt),
KeyUpdateSpotted(&'a yazi_parser::mgr::UpdateSpottedOpt),
KeyUpdateTasks(&'a yazi_parser::mgr::UpdateTasksOpt),
KeyUpdateYanked(&'a yazi_parser::mgr::UpdateYankedOpt<'a>),
KeyVisualMode(&'a yazi_parser::mgr::VisualModeOpt),
KeyWatch(&'a yazi_parser::VoidOpt),
KeyYank(&'a yazi_parser::mgr::YankOpt),
// Void
Void(&'a yazi_parser::VoidOpt),
} }
impl Body<'static> { impl Body<'static> {
@ -44,7 +108,6 @@ impl Body<'static> {
"trash" => Self::Trash(serde_json::from_str(body)?), "trash" => Self::Trash(serde_json::from_str(body)?),
"delete" => Self::Delete(serde_json::from_str(body)?), "delete" => Self::Delete(serde_json::from_str(body)?),
"mount" => Self::Mount(serde_json::from_str(body)?), "mount" => Self::Mount(serde_json::from_str(body)?),
"before-quit" => Self::BeforeQuit(serde_json::from_str(body)?),
_ => BodyCustom::from_str(kind, body)?, _ => BodyCustom::from_str(kind, body)?,
}) })
} }
@ -71,8 +134,13 @@ impl Body<'static> {
| "trash" | "trash"
| "delete" | "delete"
| "mount" | "mount"
| "before-quit" ) || kind.starts_with("emit-")
) { || kind.starts_with("emit-ind-")
|| kind.starts_with("ind-")
|| kind.starts_with("key-")
|| kind.starts_with("relay-")
|| kind.starts_with("relay-ind-")
{
bail!("Cannot construct system event"); bail!("Cannot construct system event");
} }
@ -106,8 +174,74 @@ impl<'a> Body<'a> {
Self::Trash(_) => "trash", Self::Trash(_) => "trash",
Self::Delete(_) => "delete", Self::Delete(_) => "delete",
Self::Mount(_) => "mount", Self::Mount(_) => "mount",
Self::BeforeQuit(_) => "before-quit",
Self::Custom(b) => b.kind.as_str(), Self::Custom(b) => b.kind.as_str(),
// Manager key events
Self::KeyArrow(_) => "key-arrow",
Self::KeyBack(_) => "key-back",
Self::KeyBulkRename(_) => "key-bulk-rename",
Self::KeyCd(_) => "key-cd",
Self::KeyClose(_) => "key-close",
Self::KeyCopy(_) => "key-copy",
Self::KeyCreate(_) => "key-create",
Self::KeyEnter(_) => "key-enter",
Self::KeyEscape(_) => "key-escape",
Self::KeyEscapeFilter(_) => "key-escape-filter",
Self::KeyEscapeFind(_) => "key-escape-find",
Self::KeyEscapeSearch(_) => "key-escape-search",
Self::KeyEscapeSelect(_) => "key-escape-select",
Self::KeyEscapeVisual(_) => "key-escape-visual",
Self::KeyFilter(_) => "key-filter",
Self::KeyFilterDo(_) => "key-filter-do",
Self::KeyFind(_) => "key-find",
Self::KeyFindArrow(_) => "key-find-arrow",
Self::KeyFindDo(_) => "key-find-do",
Self::KeyFollow(_) => "key-follow",
Self::KeyForward(_) => "key-forward",
Self::KeyHardlink(_) => "key-hardlink",
Self::KeyHidden(_) => "key-hidden",
Self::KeyHover(_) => "key-hover",
Self::KeyHoverDo(_) => "key-hover-do",
Self::KeyLeave(_) => "key-leave",
Self::KeyLinemode(_) => "key-linemode",
Self::KeyLink(_) => "key-link",
Self::KeyOpen(_) => "key-open",
Self::KeyOpenDo(_) => "key-open-do",
Self::KeyPaste(_) => "key-paste",
Self::KeyPeek(_) => "key-peek",
Self::KeyQuit(_) => "key-quit",
Self::KeyRefresh(_) => "key-refresh",
Self::KeyRemove(_) => "key-remove",
Self::KeyRemoveDo(_) => "key-remove-do",
Self::KeyRename(_) => "key-rename",
Self::KeyReveal(_) => "key-reveal",
Self::KeySearch(_) => "key-search",
Self::KeySearchDo(_) => "key-search-do",
Self::KeySearchStop(_) => "key-search-stop",
Self::KeySeek(_) => "key-seek",
Self::KeyShell(_) => "key-shell",
Self::KeySort(_) => "key-sort",
Self::KeySpot(_) => "key-spot",
Self::KeySuspend(_) => "key-suspend",
Self::KeyTabClose(_) => "key-tab-close",
Self::KeyTabCreate(_) => "key-tab-create",
Self::KeyTabSwap(_) => "key-tab-swap",
Self::KeyTabSwitch(_) => "key-tab-switch",
Self::KeyToggle(_) => "key-toggle",
Self::KeyToggleAll(_) => "key-toggle-all",
Self::KeyUnyank(_) => "key-unyank",
Self::KeyUpdateFiles(_) => "key-update-files",
Self::KeyUpdateMimes(_) => "key-update-mimes",
Self::KeyUpdatePaged(_) => "key-update-paged",
Self::KeyUpdatePeeked(_) => "key-update-peeked",
Self::KeyUpdateSpotted(_) => "key-update-spotted",
Self::KeyUpdateTasks(_) => "key-update-tasks",
Self::KeyUpdateYanked(_) => "key-update-yanked",
Self::KeyVisualMode(_) => "key-visual-mode",
Self::KeyWatch(_) => "key-watch",
Self::KeyYank(_) => "key-yank",
// Void
Self::Void(_) => "void",
} }
} }
@ -120,7 +254,7 @@ impl<'a> Body<'a> {
pub fn with_sender(self, sender: Id) -> Payload<'a> { Payload::new(self).with_sender(sender) } pub fn with_sender(self, sender: Id) -> Payload<'a> { Payload::new(self).with_sender(sender) }
} }
impl IntoLua for Body<'static> { impl<'a> IntoLua for Body<'a> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
match self { match self {
Self::Hi(b) => b.into_lua(lua), Self::Hi(b) => b.into_lua(lua),
@ -137,8 +271,74 @@ impl IntoLua for Body<'static> {
Self::Trash(b) => b.into_lua(lua), Self::Trash(b) => b.into_lua(lua),
Self::Delete(b) => b.into_lua(lua), Self::Delete(b) => b.into_lua(lua),
Self::Mount(b) => b.into_lua(lua), Self::Mount(b) => b.into_lua(lua),
Self::BeforeQuit(b) => b.into_lua(lua),
Self::Custom(b) => b.into_lua(lua), Self::Custom(b) => b.into_lua(lua),
// Manager key events
Self::KeyArrow(b) => b.into_lua(lua),
Self::KeyBack(b) => b.into_lua(lua),
Self::KeyBulkRename(b) => b.into_lua(lua),
Self::KeyCd(b) => b.into_lua(lua),
Self::KeyClose(b) => b.into_lua(lua),
Self::KeyCopy(b) => b.into_lua(lua),
Self::KeyCreate(b) => b.into_lua(lua),
Self::KeyEnter(b) => b.into_lua(lua),
Self::KeyEscape(b) => b.into_lua(lua),
Self::KeyEscapeFilter(b) => b.into_lua(lua),
Self::KeyEscapeFind(b) => b.into_lua(lua),
Self::KeyEscapeSearch(b) => b.into_lua(lua),
Self::KeyEscapeSelect(b) => b.into_lua(lua),
Self::KeyEscapeVisual(b) => b.into_lua(lua),
Self::KeyFilter(b) => b.into_lua(lua),
Self::KeyFilterDo(b) => b.into_lua(lua),
Self::KeyFind(b) => b.into_lua(lua),
Self::KeyFindArrow(b) => b.into_lua(lua),
Self::KeyFindDo(b) => b.into_lua(lua),
Self::KeyFollow(b) => b.into_lua(lua),
Self::KeyForward(b) => b.into_lua(lua),
Self::KeyHardlink(b) => b.into_lua(lua),
Self::KeyHidden(b) => b.into_lua(lua),
Self::KeyHover(b) => b.into_lua(lua),
Self::KeyHoverDo(b) => b.into_lua(lua),
Self::KeyLeave(b) => b.into_lua(lua),
Self::KeyLinemode(b) => b.into_lua(lua),
Self::KeyLink(b) => b.into_lua(lua),
Self::KeyOpen(b) => b.into_lua(lua),
Self::KeyOpenDo(b) => b.into_lua(lua),
Self::KeyPaste(b) => b.into_lua(lua),
Self::KeyPeek(b) => b.into_lua(lua),
Self::KeyQuit(b) => b.into_lua(lua),
Self::KeyRefresh(b) => b.into_lua(lua),
Self::KeyRemove(b) => b.into_lua(lua),
Self::KeyRemoveDo(b) => b.into_lua(lua),
Self::KeyRename(b) => b.into_lua(lua),
Self::KeyReveal(b) => b.into_lua(lua),
Self::KeySearch(b) => b.into_lua(lua),
Self::KeySearchDo(b) => b.into_lua(lua),
Self::KeySearchStop(b) => b.into_lua(lua),
Self::KeySeek(b) => b.into_lua(lua),
Self::KeyShell(b) => b.into_lua(lua),
Self::KeySort(b) => b.into_lua(lua),
Self::KeySpot(b) => b.into_lua(lua),
Self::KeySuspend(b) => b.into_lua(lua),
Self::KeyTabClose(b) => b.into_lua(lua),
Self::KeyTabCreate(b) => b.into_lua(lua),
Self::KeyTabSwap(b) => b.into_lua(lua),
Self::KeyTabSwitch(b) => b.into_lua(lua),
Self::KeyToggle(b) => b.into_lua(lua),
Self::KeyToggleAll(b) => b.into_lua(lua),
Self::KeyUnyank(b) => b.into_lua(lua),
Self::KeyUpdateFiles(b) => b.into_lua(lua),
Self::KeyUpdateMimes(b) => b.into_lua(lua),
Self::KeyUpdatePaged(b) => b.into_lua(lua),
Self::KeyUpdatePeeked(b) => b.into_lua(lua),
Self::KeyUpdateSpotted(b) => b.into_lua(lua),
Self::KeyUpdateTasks(b) => b.into_lua(lua),
Self::KeyUpdateYanked(b) => b.into_lua(lua),
Self::KeyVisualMode(b) => b.into_lua(lua),
Self::KeyWatch(b) => b.into_lua(lua),
Self::KeyYank(b) => b.into_lua(lua),
// Void
Self::Void(b) => b.into_lua(lua),
} }
} }
} }

View file

@ -1,6 +1,6 @@
use std::{borrow::Cow, collections::{HashMap, hash_map}}; use std::{borrow::Cow, collections::HashMap};
use mlua::{AnyUserData, IntoLua, IntoLuaMulti, Lua, MetaMethod, UserData, UserDataRefMut, Value}; use mlua::{IntoLua, Lua, Value};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use yazi_shared::url::Url; use yazi_shared::url::Url;
@ -34,32 +34,15 @@ impl<'a> From<BodyBulk<'a>> for Body<'a> {
fn from(value: BodyBulk<'a>) -> Self { Self::Bulk(value) } fn from(value: BodyBulk<'a>) -> Self { Self::Bulk(value) }
} }
impl IntoLua for BodyBulk<'static> { impl IntoLua for BodyBulk<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
BodyBulkIter { inner: self.changes.into_iter() }.into_lua(lua) lua
} .create_table_from(
} self
.changes
// --- Iterator .into_iter()
// TODO: use `yazi_binding::Iter` instead .map(|(from, to)| (yazi_binding::Url::new(from), yazi_binding::Url::new(to))),
pub struct BodyBulkIter { )?
pub inner: hash_map::IntoIter<Cow<'static, Url>, Cow<'static, Url>>, .into_lua(lua)
}
impl UserData for BodyBulkIter {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.inner.len()));
methods.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| {
let iter = lua.create_function(|lua, mut me: UserDataRefMut<Self>| {
if let Some((Cow::Owned(from), Cow::Owned(to))) = me.inner.next() {
(yazi_binding::Url::new(from), yazi_binding::Url::new(to)).into_lua_multi(lua)
} else {
().into_lua_multi(lua)
}
})?;
Ok((iter, me))
});
} }
} }

View file

@ -30,7 +30,7 @@ impl<'a> From<BodyCd<'a>> for Body<'a> {
fn from(value: BodyCd<'a>) -> Self { Self::Cd(value) } fn from(value: BodyCd<'a>) -> Self { Self::Cd(value) }
} }
impl IntoLua for BodyCd<'static> { impl IntoLua for BodyCd<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua lua
.create_table_from([ .create_table_from([

View file

@ -23,7 +23,7 @@ impl<'a> From<BodyDelete<'a>> for Body<'a> {
fn from(value: BodyDelete<'a>) -> Self { Self::Delete(value) } fn from(value: BodyDelete<'a>) -> Self { Self::Delete(value) }
} }
impl IntoLua for BodyDelete<'static> { impl IntoLua for BodyDelete<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
let urls = let urls =
lua.create_sequence_from(self.urls.into_owned().into_iter().map(yazi_binding::Url::new))?; lua.create_sequence_from(self.urls.into_owned().into_iter().map(yazi_binding::Url::new))?;

View file

@ -26,7 +26,7 @@ impl<'a> From<BodyHover<'a>> for Body<'a> {
fn from(value: BodyHover<'a>) -> Self { Self::Hover(value) } fn from(value: BodyHover<'a>) -> Self { Self::Hover(value) }
} }
impl IntoLua for BodyHover<'static> { impl IntoLua for BodyHover<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua lua
.create_table_from([ .create_table_from([

View file

@ -30,7 +30,7 @@ impl<'a> From<BodyLoad<'a>> for Body<'a> {
fn from(value: BodyLoad<'a>) -> Self { Self::Load(value) } fn from(value: BodyLoad<'a>) -> Self { Self::Load(value) }
} }
impl IntoLua for BodyLoad<'static> { impl IntoLua for BodyLoad<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua lua
.create_table_from([ .create_table_from([

View file

@ -1,5 +1,5 @@
#![allow(clippy::module_inception)] #![allow(clippy::module_inception)]
yazi_macro::mod_flat!( yazi_macro::mod_flat!(
before_default before_quit body bulk bye cd custom delete hey hi hover load mount r#move rename tab trash yank body bulk bye cd custom delete hey hi hover load mount r#move rename tab trash yank
); );

View file

@ -27,7 +27,7 @@ impl<'a> From<BodyMove<'a>> for Body<'a> {
fn from(value: BodyMove<'a>) -> Self { Self::Move(value) } fn from(value: BodyMove<'a>) -> Self { Self::Move(value) }
} }
impl IntoLua for BodyMove<'static> { impl IntoLua for BodyMove<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua.create_table_from([("items", self.items.into_owned())])?.into_lua(lua) lua.create_table_from([("items", self.items.into_owned())])?.into_lua(lua)
} }

View file

@ -29,7 +29,7 @@ impl<'a> From<BodyRename<'a>> for Body<'a> {
fn from(value: BodyRename<'a>) -> Self { Self::Rename(value) } fn from(value: BodyRename<'a>) -> Self { Self::Rename(value) }
} }
impl IntoLua for BodyRename<'static> { impl IntoLua for BodyRename<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua lua
.create_table_from([ .create_table_from([

View file

@ -23,7 +23,7 @@ impl<'a> From<BodyTrash<'a>> for Body<'a> {
fn from(value: BodyTrash<'a>) -> Self { Self::Trash(value) } fn from(value: BodyTrash<'a>) -> Self { Self::Trash(value) }
} }
impl IntoLua for BodyTrash<'static> { impl IntoLua for BodyTrash<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
let urls = let urls =
lua.create_sequence_from(self.urls.into_owned().into_iter().map(yazi_binding::Url::new))?; lua.create_sequence_from(self.urls.into_owned().into_iter().map(yazi_binding::Url::new))?;

View file

@ -26,6 +26,6 @@ impl<'a> From<BodyYank<'a>> for Body<'a> {
fn from(value: BodyYank<'a>) -> Self { Self::Yank(value) } fn from(value: BodyYank<'a>) -> Self { Self::Yank(value) }
} }
impl IntoLua for BodyYank<'static> { impl IntoLua for BodyYank<'_> {
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { self.0.into_lua(lua) } fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { self.0.into_lua(lua) }
} }

View file

@ -1,8 +1,14 @@
#[macro_export] #[macro_export]
macro_rules! local_or_err { macro_rules! body {
($name:literal) => { (mgr: $name:ident, $body:expr) => {
if !$crate::LOCAL.read().contains_key($name) { paste::paste! {
anyhow::bail!("No local event handler found"); $crate::body::Body::[<Key $name:camel>]($body)
} }
}; };
($layer:ident : $name:ident, $body:expr) => {
$crate::body::Body::Void(&yazi_parser::VoidOpt)
// paste::paste! {
// $crate::body::Body::[<Key $layer:camel $name:camel>]($body)
// }
};
} }

View file

@ -2,8 +2,8 @@ use std::{fmt::Display, io::Write, str::FromStr};
use anyhow::{Result, anyhow}; use anyhow::{Result, anyhow};
use yazi_boot::BOOT; use yazi_boot::BOOT;
use yazi_macro::emit; use yazi_macro::{emit, relay};
use yazi_shared::{Id, event::Cmd}; use yazi_shared::Id;
use crate::{ID, body::Body}; use crate::{ID, body::Body};
@ -47,7 +47,7 @@ impl<'a> Payload<'a> {
impl Payload<'static> { impl Payload<'static> {
pub(super) fn emit(self) -> Result<()> { pub(super) fn emit(self) -> Result<()> {
self.try_flush()?; self.try_flush()?;
emit!(Call(Cmd::new("app:accept_payload").with_any("payload", self))); emit!(Call(relay!(app:accept_payload).with_any("payload", self)));
Ok(()) Ok(())
} }
} }
@ -93,8 +93,8 @@ impl Display for Payload<'_> {
Body::Trash(b) => serde_json::to_string(b), Body::Trash(b) => serde_json::to_string(b),
Body::Delete(b) => serde_json::to_string(b), Body::Delete(b) => serde_json::to_string(b),
Body::Mount(b) => serde_json::to_string(b), Body::Mount(b) => serde_json::to_string(b),
Body::BeforeQuit(b) => serde_json::to_string(b),
Body::Custom(b) => serde_json::to_string(b), Body::Custom(b) => serde_json::to_string(b),
_ => return Err(std::fmt::Error),
}; };
if let Ok(s) = result { if let Ok(s) = result {

View file

@ -44,9 +44,7 @@ anyhow = { workspace = true }
better-panic = "0.3.0" better-panic = "0.3.0"
crossterm = { workspace = true } crossterm = { workspace = true }
fdlimit = "0.3.0" fdlimit = "0.3.0"
foldhash = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
indexmap = { workspace = true }
mlua = { workspace = true } mlua = { workspace = true }
paste = { workspace = true } paste = { workspace = true }
ratatui = { workspace = true } ratatui = { workspace = true }

View file

@ -21,7 +21,6 @@ impl App {
let mut app = Self { core: Core::make(), term: Some(term), signals }; let mut app = Self { core: Core::make(), term: Some(term), signals };
act!(bootstrap, app)?; act!(bootstrap, app)?;
act!(render, app)?;
let mut events = Vec::with_capacity(50); let mut events = Vec::with_capacity(50);
let (mut timeout, mut last_render) = (None, Instant::now()); let (mut timeout, mut last_render) = (None, Instant::now());

View file

@ -1,14 +1,14 @@
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use mlua::{IntoLua, Value}; use mlua::IntoLua;
use tracing::error; use tracing::error;
use yazi_actor::lives::Lives;
use yazi_binding::runtime_mut; use yazi_binding::runtime_mut;
use yazi_core::Core; use yazi_dds::{LOCAL, Payload, REMOTE};
use yazi_dds::{LOCAL, Payload, REMOTE, body::Body};
use yazi_macro::succ; use yazi_macro::succ;
use yazi_plugin::LUA; use yazi_plugin::LUA;
use yazi_shared::event::{CmdCow, Data}; use yazi_shared::event::{CmdCow, Data};
use crate::{app::App, lives::Lives}; use crate::app::App;
impl App { impl App {
pub(crate) fn accept_payload(&self, mut c: CmdCow) -> Result<Data> { pub(crate) fn accept_payload(&self, mut c: CmdCow) -> Result<Data> {
@ -38,32 +38,4 @@ impl App {
Ok(()) Ok(())
})?); })?);
} }
// FIXME: find a better name
pub(crate) fn accept_payload2(core: &Core, body: Body<'static>) -> Result<Data> {
let kind = body.kind();
let Some(handlers) = LOCAL.read().get(kind).filter(|&m| !m.is_empty()).cloned() else {
succ!(false)
};
let kind = kind.to_owned();
succ!(Lives::scope(core, || {
let body = body.into_lua(&LUA)?;
for (id, cb) in handlers {
runtime_mut!(LUA)?.push(&id);
let result = cb.call::<Value>(body.clone());
runtime_mut!(LUA)?.pop();
match result {
Ok(Value::Boolean(true)) => return Ok(true),
Ok(Value::Nil | Value::Boolean(false)) => {}
Ok(v) => {
error!("Unexpected return type from `{kind}` event handler in `{id}` plugin: {v:?}")
}
Err(e) => error!("Failed to run `{kind}` event handler in `{id}` plugin: {e}"),
}
}
Ok(false)
})?);
}
} }

View file

@ -1,7 +1,7 @@
use anyhow::Result; use anyhow::Result;
use yazi_actor::Ctx; use yazi_actor::Ctx;
use yazi_boot::BOOT; use yazi_boot::BOOT;
use yazi_macro::{act, succ}; use yazi_macro::act;
use yazi_parser::{VoidOpt, mgr::CdSource}; use yazi_parser::{VoidOpt, mgr::CdSource};
use yazi_shared::{event::Data, url::Url}; use yazi_shared::{event::Data, url::Url};
@ -15,7 +15,9 @@ impl App {
tabs.push(Default::default()); tabs.push(Default::default());
} }
let cx = &mut Ctx { core: &mut self.core, tab: i }; let cx = &mut Ctx::active(&mut self.core);
cx.tab = i;
if file.is_empty() { if file.is_empty() {
act!(mgr:cd, cx, (Url::from(&BOOT.cwds[i]), CdSource::Tab))?; act!(mgr:cd, cx, (Url::from(&BOOT.cwds[i]), CdSource::Tab))?;
} else { } else {
@ -23,6 +25,6 @@ impl App {
} }
} }
succ!(); act!(render, self)
} }
} }

View file

@ -2,13 +2,14 @@ use anyhow::Result;
use crossterm::event::MouseEventKind; use crossterm::event::MouseEventKind;
use mlua::{ObjectLike, Table}; use mlua::{ObjectLike, Table};
use tracing::error; use tracing::error;
use yazi_actor::lives::Lives;
use yazi_config::YAZI; use yazi_config::YAZI;
use yazi_macro::succ; use yazi_macro::succ;
use yazi_parser::app::MouseOpt; use yazi_parser::app::MouseOpt;
use yazi_plugin::LUA; use yazi_plugin::LUA;
use yazi_shared::event::Data; use yazi_shared::event::Data;
use crate::{app::App, lives::Lives}; use crate::app::App;
impl App { impl App {
pub fn mouse(&mut self, opt: MouseOpt) -> Result<Data> { pub fn mouse(&mut self, opt: MouseOpt) -> Result<Data> {

View file

@ -2,6 +2,7 @@ use anyhow::Result;
use mlua::ObjectLike; use mlua::ObjectLike;
use scopeguard::defer; use scopeguard::defer;
use tracing::{error, warn}; use tracing::{error, warn};
use yazi_actor::lives::Lives;
use yazi_binding::runtime_mut; use yazi_binding::runtime_mut;
use yazi_dds::Sendable; use yazi_dds::Sendable;
use yazi_macro::succ; use yazi_macro::succ;
@ -10,7 +11,7 @@ use yazi_plugin::{LUA, loader::{LOADER, Loader}};
use yazi_proxy::AppProxy; use yazi_proxy::AppProxy;
use yazi_shared::event::Data; use yazi_shared::event::Data;
use crate::{app::App, lives::Lives}; use crate::app::App;
impl App { impl App {
pub(crate) fn plugin(&mut self, mut opt: PluginOpt) -> Result<Data> { pub(crate) fn plugin(&mut self, mut opt: PluginOpt) -> Result<Data> {

View file

@ -2,12 +2,13 @@ use anyhow::Result;
use mlua::Value; use mlua::Value;
use ratatui::layout::Position; use ratatui::layout::Position;
use tracing::error; use tracing::error;
use yazi_actor::lives::Lives;
use yazi_config::LAYOUT; use yazi_config::LAYOUT;
use yazi_macro::{render, succ}; use yazi_macro::{render, succ};
use yazi_parser::VoidOpt; use yazi_parser::VoidOpt;
use yazi_shared::event::Data; use yazi_shared::event::Data;
use crate::{Root, app::App, lives::Lives}; use crate::{Root, app::App};
impl App { impl App {
pub fn reflow(&mut self, _: VoidOpt) -> Result<Data> { pub fn reflow(&mut self, _: VoidOpt) -> Result<Data> {

View file

@ -3,14 +3,14 @@ use std::sync::atomic::{AtomicU8, Ordering};
use anyhow::Result; use anyhow::Result;
use crossterm::{cursor::{MoveTo, SetCursorStyle, Show}, execute, queue, terminal::{BeginSynchronizedUpdate, EndSynchronizedUpdate}}; use crossterm::{cursor::{MoveTo, SetCursorStyle, Show}, execute, queue, terminal::{BeginSynchronizedUpdate, EndSynchronizedUpdate}};
use ratatui::{CompletedFrame, backend::{Backend, CrosstermBackend}, buffer::Buffer, layout::Position}; use ratatui::{CompletedFrame, backend::{Backend, CrosstermBackend}, buffer::Buffer, layout::Position};
use yazi_actor::Ctx; use yazi_actor::{Ctx, lives::Lives};
use yazi_binding::elements::COLLISION; use yazi_binding::elements::COLLISION;
use yazi_macro::{act, succ}; use yazi_macro::{act, succ};
use yazi_parser::VoidOpt; use yazi_parser::VoidOpt;
use yazi_shared::event::{Data, NEED_RENDER}; use yazi_shared::event::{Data, NEED_RENDER};
use yazi_term::tty::TTY; use yazi_term::tty::TTY;
use crate::{app::App, lives::Lives, root::Root}; use crate::{app::App, root::Root};
impl App { impl App {
pub(crate) fn render(&mut self, _: VoidOpt) -> Result<Data> { pub(crate) fn render(&mut self, _: VoidOpt) -> Result<Data> {
@ -36,7 +36,8 @@ impl App {
// Reload preview if collision is resolved // Reload preview if collision is resolved
if collision && !COLLISION.load(Ordering::Relaxed) { if collision && !COLLISION.load(Ordering::Relaxed) {
act!(mgr:peek, &mut Ctx::active(&mut self.core), true)?; let cx = &mut Ctx::active(&mut self.core);
act!(mgr:peek, cx, true)?;
} }
succ!(); succ!();
} }

View file

@ -14,6 +14,7 @@ impl App {
self.core.parent_mut().map(|f| f.arrow(0)); self.core.parent_mut().map(|f| f.arrow(0));
self.core.current_mut().sync_page(true); self.core.current_mut().sync_page(true);
act!(mgr:peek, &mut Ctx::active(&mut self.core)) let cx = &mut Ctx::active(&mut self.core);
act!(mgr:peek, cx)
} }
} }

View file

@ -18,7 +18,8 @@ impl App {
let new = tasks.paginate(); let new = tasks.paginate();
if tasks.summaries != new { if tasks.summaries != new {
tasks.summaries = new; tasks.summaries = new;
act!(tasks:arrow, &mut Ctx::active(&mut self.core))?; let cx = &mut Ctx::active(&mut self.core);
act!(tasks:arrow, cx)?;
succ!(render!()); succ!(render!());
} }
} }

View file

@ -1,6 +1,5 @@
use anyhow::Result; use anyhow::Result;
use yazi_actor::{Actor, Ctx}; use yazi_actor::Ctx;
use yazi_dds::body::Body;
use yazi_macro::{act, succ}; use yazi_macro::{act, succ};
use yazi_shared::{Layer, event::{CmdCow, Data}}; use yazi_shared::{Layer, event::{CmdCow, Data}};
use yazi_widgets::input::InputMode; use yazi_widgets::input::InputMode;
@ -57,16 +56,10 @@ impl<'a> Executor<'a> {
fn mgr(&mut self, cmd: CmdCow) -> Result<Data> { fn mgr(&mut self, cmd: CmdCow) -> Result<Data> {
let cx = &mut Ctx::new(&mut self.app.core, &cmd)?; let cx = &mut Ctx::new(&mut self.app.core, &cmd)?;
// FIXME: move the DDS part to `yazi-actor`
macro_rules! on { macro_rules! on {
($name:ident) => { ($name:ident) => {
if cmd.name == stringify!($name) { if cmd.name == stringify!($name) {
let opt = <act!(mgr:$name) as Actor>::Options::try_from(cmd)?; return act!(mgr:$name, cx, cmd)
return if let Ok(body) = Body::try_from(&opt) && App::accept_payload2(cx.core, body)? == true {
succ!()
} else {
act!(mgr:$name, cx, opt)
};
} }
}; };
} }

View file

@ -4,7 +4,7 @@
#[global_allocator] #[global_allocator]
static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
yazi_macro::mod_pub!(app cmp confirm help input lives mgr notify pick spot tasks which); yazi_macro::mod_pub!(app cmp confirm help input mgr notify pick spot tasks which);
yazi_macro::mod_flat!(dispatcher executor logs panic root router signals term); yazi_macro::mod_flat!(dispatcher executor logs panic root router signals term);

View file

@ -1,6 +1,7 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use yazi_shared::{Id, Ids, event::Cmd, url::{Url, UrnBuf}}; use yazi_macro::relay;
use yazi_shared::{Id, Ids, url::{Url, UrnBuf}};
use super::File; use super::File;
use crate::{cha::Cha, maybe_exists}; use crate::{cha::Cha, maybe_exists};
@ -40,8 +41,7 @@ impl FilesOp {
#[inline] #[inline]
pub fn emit(self) { pub fn emit(self) {
yazi_shared::event::Event::Call(Cmd::new("mgr:update_files").with_any("op", self).into()) yazi_shared::event::Event::Call(relay!(mgr:update_files).with_any("op", self).into()).emit();
.emit();
} }
pub fn prepare(cwd: &Url) -> Id { pub fn prepare(cwd: &Url) -> Id {

View file

@ -1,22 +1,37 @@
#[macro_export] #[macro_export]
macro_rules! act { macro_rules! act {
($layer:ident : $name:ident, $cx:expr, $cmd:expr) => {{ (@pre $layer:ident : $name:ident, $cx:ident, $opt:ident) => {
#[allow(unused_imports)] <act!($layer:$name) as yazi_actor::Actor>::hook($cx, &$opt).map(|hook| {
use ::yazi_actor::Actor; <act!(core:preflight) as yazi_actor::Actor>::act($cx, (hook, yazi_dds::body!($layer:$name, &$opt)))
<act!($layer:$name)>::act($cx, $cmd.try_into()?) })
}};
($layer:ident : $name:ident, $cx:expr) => {{
#[allow(unused_imports)]
use yazi_actor::Actor;
<act!($layer:$name)>::act($cx, Default::default())
}};
($name:ident, $cx:expr, $cmd:expr) => {
$cx.$name($cmd.try_into()?)
}; };
($name:ident, $cx:expr) => { (@impl $layer:ident : $name:ident, $cx:ident, $opt:ident) => {{
$cx.$name(Default::default()) $cx.level += 1;
let result = match act!(@pre $layer:$name, $cx, $opt) {
None | Some(Ok(yazi_shared::event::Data::Boolean(false))) => <act!($layer:$name) as yazi_actor::Actor>::act($cx, $opt),
Some(Ok(_)) => Err(anyhow::anyhow!("canceled on preflight")),
Some(e @ Err(_)) => e,
};
$cx.level -= 1;
result
}};
($layer:ident : $name:ident, $cx:ident, $cmd:expr) => {
<act!($layer:$name) as yazi_actor::Actor>::Options::try_from($cmd)
.map_err(anyhow::Error::from)
.and_then(|opt| act!(@impl $layer:$name, $cx, opt))
};
($layer:ident : $name:ident, $cx:ident) => {
act!($layer:$name, $cx, <<act!($layer:$name) as yazi_actor::Actor>::Options as Default>::default())
}; };
($layer:ident : $name:ident) => { ($layer:ident : $name:ident) => {
paste::paste! { yazi_actor::$layer::[<$name:camel>] } paste::paste! { yazi_actor::$layer::[<$name:camel>] }
}; };
($name:ident, $cx:expr, $cmd:expr) => {
$cmd.try_into().map_err(anyhow::Error::from).and_then(|opt| $cx.$name(opt))
};
($name:ident, $cx:expr) => {
$cx.$name(Default::default())
};
} }

View file

@ -14,6 +14,19 @@ macro_rules! emit {
}; };
} }
#[macro_export]
macro_rules! relay {
($layer:ident : $name:ident) => {
yazi_shared::event::Cmd::new_relay(concat!(stringify!($layer), ":", stringify!($name)))
};
($layer:ident : $name:ident, $args:expr) => {
yazi_shared::event::Cmd::new_relay_args(
concat!(stringify!($layer), ":", stringify!($name)),
$args,
)
};
}
#[macro_export] #[macro_export]
macro_rules! succ { macro_rules! succ {
($data:expr) => { ($data:expr) => {
@ -23,34 +36,3 @@ macro_rules! succ {
return Ok(yazi_shared::event::Data::Nil) return Ok(yazi_shared::event::Data::Nil)
}; };
} }
#[macro_export]
macro_rules! render {
() => {
yazi_shared::event::NEED_RENDER.store(true, std::sync::atomic::Ordering::Relaxed);
};
($cond:expr) => {
if $cond {
render!();
}
};
($left:expr, > $right:expr) => {{
let val = $left;
if val > $right {
render!();
}
val
}};
}
#[macro_export]
macro_rules! render_and {
($cond:expr) => {
if $cond {
yazi_macro::render!();
true
} else {
false
}
};
}

View file

@ -5,4 +5,5 @@ mod fmt;
mod log; mod log;
mod module; mod module;
mod platform; mod platform;
mod render;
mod stdio; mod stdio;

30
yazi-macro/src/render.rs Normal file
View file

@ -0,0 +1,30 @@
#[macro_export]
macro_rules! render {
() => {
yazi_shared::event::NEED_RENDER.store(true, std::sync::atomic::Ordering::Relaxed);
};
($cond:expr) => {
if $cond {
render!();
}
};
($left:expr, > $right:expr) => {{
let val = $left;
if val > $right {
render!();
}
val
}};
}
#[macro_export]
macro_rules! render_and {
($cond:expr) => {
if $cond {
yazi_macro::render!();
true
} else {
false
}
};
}

View file

@ -8,6 +8,10 @@ description = "Yazi command parser"
homepage = "https://yazi-rs.github.io" homepage = "https://yazi-rs.github.io"
repository = "https://github.com/sxyazi/yazi" repository = "https://github.com/sxyazi/yazi"
[features]
default = [ "vendored-lua" ]
vendored-lua = [ "mlua/vendored" ]
[dependencies] [dependencies]
yazi-binding = { path = "../yazi-binding", version = "25.6.11" } yazi-binding = { path = "../yazi-binding", version = "25.6.11" }
yazi-boot = { path = "../yazi-boot", version = "25.6.11" } yazi-boot = { path = "../yazi-boot", version = "25.6.11" }

View file

@ -1,9 +1,10 @@
use anyhow::bail; use anyhow::bail;
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
use crate::Step; use crate::Step;
#[derive(Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct ArrowOpt { pub struct ArrowOpt {
pub step: Step, pub step: Step,
} }
@ -23,3 +24,7 @@ impl TryFrom<CmdCow> for ArrowOpt {
impl From<isize> for ArrowOpt { impl From<isize> for ArrowOpt {
fn from(n: isize) -> Self { Self { step: n.into() } } fn from(n: isize) -> Self { Self { step: n.into() } }
} }
impl IntoLua for ArrowOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1 +1 @@
yazi_macro::mod_flat!(backspace backward close complete delete insert kill r#move paste show); yazi_macro::mod_flat!(backspace backward close complete delete forward insert kill paste r#move show);

View file

@ -1 +0,0 @@

View file

@ -1,6 +1,8 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_fs::expand_path; use yazi_fs::expand_path;
use yazi_shared::{event::CmdCow, url::Url}; use yazi_shared::{event::CmdCow, url::Url};
#[derive(Debug)]
pub struct CdOpt { pub struct CdOpt {
pub target: Url, pub target: Url,
pub interactive: bool, pub interactive: bool,
@ -21,8 +23,12 @@ impl From<(Url, CdSource)> for CdOpt {
fn from((target, source): (Url, CdSource)) -> Self { Self { target, interactive: false, source } } fn from((target, source): (Url, CdSource)) -> Self { Self { target, interactive: false, source } }
} }
impl IntoLua for &CdOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}
// --- Source // --- Source
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CdSource { pub enum CdSource {
Tab, Tab,
Cd, Cd,

View file

@ -1,10 +1,15 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
use crate::mgr::QuitOpt; use crate::mgr::QuitOpt;
#[derive(Default)] #[derive(Debug, Default)]
pub struct CloseOpt(pub QuitOpt); pub struct CloseOpt(pub QuitOpt);
impl From<CmdCow> for CloseOpt { impl From<CmdCow> for CloseOpt {
fn from(c: CmdCow) -> Self { Self(c.into()) } fn from(c: CmdCow) -> Self { Self(c.into()) }
} }
impl IntoLua for &CloseOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,7 +1,9 @@
use std::{borrow::Cow, ffi::OsStr, path::Path}; use std::{borrow::Cow, ffi::OsStr, path::Path};
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::{SStr, event::CmdCow}; use yazi_shared::{SStr, event::CmdCow};
#[derive(Debug)]
pub struct CopyOpt { pub struct CopyOpt {
pub r#type: SStr, pub r#type: SStr,
pub separator: CopySeparator, pub separator: CopySeparator,
@ -18,8 +20,12 @@ impl From<CmdCow> for CopyOpt {
} }
} }
impl IntoLua for &CopyOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}
// --- Separator // --- Separator
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CopySeparator { pub enum CopySeparator {
Auto, Auto,
Unix, Unix,

View file

@ -1,5 +1,7 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct CreateOpt { pub struct CreateOpt {
pub dir: bool, pub dir: bool,
pub force: bool, pub force: bool,
@ -8,3 +10,7 @@ pub struct CreateOpt {
impl From<CmdCow> for CreateOpt { impl From<CmdCow> for CreateOpt {
fn from(c: CmdCow) -> Self { Self { dir: c.bool("dir"), force: c.bool("force") } } fn from(c: CmdCow) -> Self { Self { dir: c.bool("dir"), force: c.bool("force") } }
} }
impl IntoLua for &CreateOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1 +0,0 @@

View file

@ -1,7 +1,9 @@
use bitflags::bitflags; use bitflags::bitflags;
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
bitflags! { bitflags! {
#[derive(Debug)]
pub struct EscapeOpt: u8 { pub struct EscapeOpt: u8 {
const FIND = 0b00001; const FIND = 0b00001;
const VISUAL = 0b00010; const VISUAL = 0b00010;
@ -26,3 +28,7 @@ impl From<CmdCow> for EscapeOpt {
}) })
} }
} }
impl IntoLua for &EscapeOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,7 +1,8 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_fs::FilterCase; use yazi_fs::FilterCase;
use yazi_shared::{SStr, event::CmdCow}; use yazi_shared::{SStr, event::CmdCow};
#[derive(Default)] #[derive(Debug, Default)]
pub struct FilterOpt { pub struct FilterOpt {
pub query: SStr, pub query: SStr,
pub case: FilterCase, pub case: FilterCase,
@ -23,3 +24,7 @@ impl TryFrom<CmdCow> for FilterOpt {
}) })
} }
} }
impl IntoLua for &FilterOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,6 +1,8 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_fs::FilterCase; use yazi_fs::FilterCase;
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct FindOpt { pub struct FindOpt {
pub prev: bool, pub prev: bool,
pub case: FilterCase, pub case: FilterCase,
@ -13,3 +15,7 @@ impl TryFrom<CmdCow> for FindOpt {
Ok(Self { prev: c.bool("previous"), case: FilterCase::from(&*c) }) Ok(Self { prev: c.bool("previous"), case: FilterCase::from(&*c) })
} }
} }
impl IntoLua for &FindOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,5 +1,7 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct FindArrowOpt { pub struct FindArrowOpt {
pub prev: bool, pub prev: bool,
} }
@ -7,3 +9,7 @@ pub struct FindArrowOpt {
impl From<CmdCow> for FindArrowOpt { impl From<CmdCow> for FindArrowOpt {
fn from(c: CmdCow) -> Self { Self { prev: c.bool("previous") } } fn from(c: CmdCow) -> Self { Self { prev: c.bool("previous") } }
} }
impl IntoLua for &FindArrowOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,7 +1,9 @@
use anyhow::bail; use anyhow::bail;
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_fs::FilterCase; use yazi_fs::FilterCase;
use yazi_shared::{SStr, event::CmdCow}; use yazi_shared::{SStr, event::CmdCow};
#[derive(Debug)]
pub struct FindDoOpt { pub struct FindDoOpt {
pub query: SStr, pub query: SStr,
pub prev: bool, pub prev: bool,
@ -23,3 +25,7 @@ impl TryFrom<CmdCow> for FindDoOpt {
Ok(Self { query, prev: c.bool("previous"), case: FilterCase::from(&*c) }) Ok(Self { query, prev: c.bool("previous"), case: FilterCase::from(&*c) })
} }
} }
impl IntoLua for &FindDoOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,5 +1,7 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct HardlinkOpt { pub struct HardlinkOpt {
pub force: bool, pub force: bool,
pub follow: bool, pub follow: bool,
@ -8,3 +10,7 @@ pub struct HardlinkOpt {
impl From<CmdCow> for HardlinkOpt { impl From<CmdCow> for HardlinkOpt {
fn from(c: CmdCow) -> Self { Self { force: c.bool("force"), follow: c.bool("follow") } } fn from(c: CmdCow) -> Self { Self { force: c.bool("force"), follow: c.bool("follow") } }
} }
impl IntoLua for &HardlinkOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,5 +1,7 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct HiddenOpt { pub struct HiddenOpt {
pub state: Option<bool>, pub state: Option<bool>,
} }
@ -15,3 +17,7 @@ impl From<CmdCow> for HiddenOpt {
Self { state } Self { state }
} }
} }
impl IntoLua for &HiddenOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,6 +1,7 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::{event::CmdCow, url::Url}; use yazi_shared::{event::CmdCow, url::Url};
#[derive(Default)] #[derive(Debug, Default)]
pub struct HoverOpt { pub struct HoverOpt {
pub url: Option<Url>, pub url: Option<Url>,
} }
@ -13,7 +14,12 @@ impl From<Option<Url>> for HoverOpt {
fn from(url: Option<Url>) -> Self { Self { url } } fn from(url: Option<Url>) -> Self { Self { url } }
} }
impl IntoLua for &HoverOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}
// --- Do // --- Do
#[derive(Debug)]
pub struct HoverDoOpt { pub struct HoverDoOpt {
pub url: Url, pub url: Url,
} }
@ -21,3 +27,7 @@ pub struct HoverDoOpt {
impl From<Url> for HoverDoOpt { impl From<Url> for HoverDoOpt {
fn from(url: Url) -> Self { Self { url } } fn from(url: Url) -> Self { Self { url } }
} }
impl IntoLua for &HoverDoOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,6 +1,8 @@
use anyhow::bail; use anyhow::bail;
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::{SStr, event::CmdCow}; use yazi_shared::{SStr, event::CmdCow};
#[derive(Debug)]
pub struct LinemodeOpt { pub struct LinemodeOpt {
pub new: SStr, pub new: SStr,
} }
@ -20,3 +22,7 @@ impl TryFrom<CmdCow> for LinemodeOpt {
Ok(Self { new }) Ok(Self { new })
} }
} }
impl IntoLua for &LinemodeOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

View file

@ -1,5 +1,7 @@
use mlua::{ExternalError, IntoLua, Lua, Value};
use yazi_shared::event::CmdCow; use yazi_shared::event::CmdCow;
#[derive(Debug)]
pub struct LinkOpt { pub struct LinkOpt {
pub relative: bool, pub relative: bool,
pub force: bool, pub force: bool,
@ -8,3 +10,7 @@ pub struct LinkOpt {
impl From<CmdCow> for LinkOpt { impl From<CmdCow> for LinkOpt {
fn from(c: CmdCow) -> Self { Self { relative: c.bool("relative"), force: c.bool("force") } } fn from(c: CmdCow) -> Self { Self { relative: c.bool("relative"), force: c.bool("force") } }
} }
impl IntoLua for &LinkOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
}

Some files were not shown because too many files have changed in this diff Show more