feat: new ind-which-show DDS event to change the which component behavior (#3608)

This commit is contained in:
三咲雅 misaki masa 2026-01-25 03:06:50 +08:00 committed by GitHub
parent afc694c122
commit face6aed40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 216 additions and 321 deletions

View file

@ -12,6 +12,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
## [Unreleased] ## [Unreleased]
### Added
- New `ind-which-show` DDS event to change the which component behavior ([#3608])
### Fixed ### Fixed
- Archive extraction fails for target paths with non-ASCII characters on Windows ([#3607]) - Archive extraction fails for target paths with non-ASCII characters on Windows ([#3607])
@ -1617,3 +1621,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
[#3582]: https://github.com/sxyazi/yazi/pull/3582 [#3582]: https://github.com/sxyazi/yazi/pull/3582
[#3594]: https://github.com/sxyazi/yazi/pull/3594 [#3594]: https://github.com/sxyazi/yazi/pull/3594
[#3607]: https://github.com/sxyazi/yazi/pull/3607 [#3607]: https://github.com/sxyazi/yazi/pull/3607
[#3608]: https://github.com/sxyazi/yazi/pull/3608

87
Cargo.lock generated
View file

@ -541,9 +541,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.53" version = "1.2.54"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"jobserver", "jobserver",
@ -919,9 +919,9 @@ dependencies = [
[[package]] [[package]]
name = "crypto-common" name = "crypto-common"
version = "0.2.0-rc.10" version = "0.2.0-rc.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f4fc0003068acd7e9cb6659fd956dc4d671f102a06cc115990b9e7bb5745c25" checksum = "c7722afd27468475c9b6063dc03a57ef2ca833816981619f8ebe64d38d207eef"
dependencies = [ dependencies = [
"hybrid-array", "hybrid-array",
] ]
@ -1203,13 +1203,13 @@ dependencies = [
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.11.0-rc.6" version = "0.11.0-rc.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2778ee7344f47967d6701053913962accf9bfdb0caa4b6d921b7c4a615f658d0" checksum = "2fc1408b7a9f59a7b933faff3e9e7fc15a05a524effd3b3d1601156944c8077f"
dependencies = [ dependencies = [
"block-buffer 0.11.0", "block-buffer 0.11.0",
"const-oid 0.10.2", "const-oid 0.10.2",
"crypto-common 0.2.0-rc.10", "crypto-common 0.2.0-rc.13",
] ]
[[package]] [[package]]
@ -1856,9 +1856,9 @@ dependencies = [
[[package]] [[package]]
name = "hybrid-array" name = "hybrid-array"
version = "0.4.5" version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f471e0a81b2f90ffc0cb2f951ae04da57de8baa46fa99112b062a5173a5088d0" checksum = "b41fb3dc24fe72c2e3a4685eed55917c2fb228851257f4a8f2d985da9443c3e5"
dependencies = [ dependencies = [
"typenum", "typenum",
] ]
@ -2004,7 +2004,7 @@ checksum = "fe44f2bbd99fcb302e246e2d6bcf51aeda346d02a365f80296a07a8c711b6da6"
dependencies = [ dependencies = [
"argon2", "argon2",
"bcrypt-pbkdf", "bcrypt-pbkdf",
"digest 0.11.0-rc.6", "digest 0.11.0-rc.8",
"ecdsa", "ecdsa",
"ed25519-dalek", "ed25519-dalek",
"hex", "hex",
@ -2017,7 +2017,7 @@ dependencies = [
"rsa", "rsa",
"sec1", "sec1",
"sha1 0.10.6", "sha1 0.10.6",
"sha1 0.11.0-rc.3", "sha1 0.11.0-rc.4",
"sha2 0.10.9", "sha2 0.10.9",
"signature 2.2.0", "signature 2.2.0",
"signature 3.0.0-rc.6", "signature 3.0.0-rc.6",
@ -2215,9 +2215,9 @@ dependencies = [
[[package]] [[package]]
name = "libm" name = "libm"
version = "0.2.15" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]] [[package]]
name = "libredox" name = "libredox"
@ -2567,9 +2567,9 @@ dependencies = [
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.1.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
[[package]] [[package]]
name = "num-derive" name = "num-derive"
@ -3264,9 +3264,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.43" version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -3628,11 +3628,11 @@ dependencies = [
"const-oid 0.10.2", "const-oid 0.10.2",
"crypto-bigint 0.7.0-rc.18", "crypto-bigint 0.7.0-rc.18",
"crypto-primes", "crypto-primes",
"digest 0.11.0-rc.6", "digest 0.11.0-rc.8",
"pkcs1", "pkcs1",
"pkcs8 0.11.0-rc.9", "pkcs8 0.11.0-rc.9",
"rand_core 0.10.0-rc-3", "rand_core 0.10.0-rc-3",
"sha2 0.11.0-rc.3", "sha2 0.11.0-rc.4",
"signature 3.0.0-rc.6", "signature 3.0.0-rc.6",
"spki 0.8.0-rc.4", "spki 0.8.0-rc.4",
"zeroize", "zeroize",
@ -3640,9 +3640,9 @@ dependencies = [
[[package]] [[package]]
name = "russh" name = "russh"
version = "0.56.0" version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdbb7dcdd62c17ac911307ff693f55b3ec6712004d2d66ffdb8c0fa00269fd66" checksum = "01fe22d10a0e39c1134a971d5b8db8a40357b48ef22d81fa8d6eac22202dd782"
dependencies = [ dependencies = [
"aes", "aes",
"bitflags 2.10.0", "bitflags 2.10.0",
@ -3680,8 +3680,8 @@ dependencies = [
"pkcs1", "pkcs1",
"pkcs5", "pkcs5",
"pkcs8 0.10.2", "pkcs8 0.10.2",
"rand 0.8.5", "rand 0.9.2",
"rand_core 0.6.4", "rand_core 0.10.0-rc-3",
"ring", "ring",
"rsa", "rsa",
"russh-cryptovec", "russh-cryptovec",
@ -3932,13 +3932,13 @@ dependencies = [
[[package]] [[package]]
name = "sha1" name = "sha1"
version = "0.11.0-rc.3" version = "0.11.0-rc.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa1ae819b9870cadc959a052363de870944a1646932d274a4e270f64bf79e5ef" checksum = "9c777f0a122a53fddb0beb6e706771197000b8eb5c9f42b5b850f450ef48c788"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
"digest 0.11.0-rc.6", "digest 0.11.0-rc.8",
] ]
[[package]] [[package]]
@ -3954,13 +3954,13 @@ dependencies = [
[[package]] [[package]]
name = "sha2" name = "sha2"
version = "0.11.0-rc.3" version = "0.11.0-rc.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19d43dc0354d88b791216bb5c1bfbb60c0814460cc653ae0ebd71f286d0bd927" checksum = "7535f94fa3339fe9e5e9be6260a909e62af97f6e14b32345ccf79b92b8b81233"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"cpufeatures", "cpufeatures",
"digest 0.11.0-rc.6", "digest 0.11.0-rc.8",
] ]
[[package]] [[package]]
@ -3990,9 +3990,9 @@ dependencies = [
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.4.1" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a37d01603c37b5466f808de79f845c7116049b0579adb70a6b7d47c1fa3a952" checksum = "3b57709da74f9ff9f4a27dce9526eec25ca8407c45a7887243b031a58935fb8e"
dependencies = [ dependencies = [
"libc", "libc",
"signal-hook-registry", "signal-hook-registry",
@ -4027,7 +4027,7 @@ checksum = "e513e435a8898a0002270f29d0a708b7879708fb5c4d00e46983ca2d2d378cf0"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"libc", "libc",
"signal-hook 0.4.1", "signal-hook 0.4.3",
"tokio", "tokio",
] ]
@ -4047,7 +4047,7 @@ version = "3.0.0-rc.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a96996ccff7dfa16f052bd995b4cecc72af22c35138738dc029f0ead6608d" checksum = "597a96996ccff7dfa16f052bd995b4cecc72af22c35138738dc029f0ead6608d"
dependencies = [ dependencies = [
"digest 0.11.0-rc.6", "digest 0.11.0-rc.8",
"rand_core 0.10.0-rc-3", "rand_core 0.10.0-rc-3",
] ]
@ -4092,9 +4092,9 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.6.1" version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.60.2", "windows-sys 0.60.2",
@ -4408,9 +4408,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.45" version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa", "itoa",
@ -4425,15 +4425,15 @@ dependencies = [
[[package]] [[package]]
name = "time-core" name = "time-core"
version = "0.1.7" version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.25" version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4"
dependencies = [ dependencies = [
"num-conv", "num-conv",
"time-core", "time-core",
@ -4653,9 +4653,9 @@ dependencies = [
[[package]] [[package]]
name = "typed-path" name = "typed-path"
version = "0.12.0" version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7922f2cdc51280d47b491af9eafc41eb0cdab85eabcb390c854412fcbf26dbe8" checksum = "e43ffa54726cdc9ea78392023ffe9fe9cf9ac779e1c6fcb0d23f9862e3879d20"
[[package]] [[package]]
name = "typeid" name = "typeid"
@ -5484,6 +5484,7 @@ dependencies = [
"tracing", "tracing",
"unicode-width", "unicode-width",
"yazi-adapter", "yazi-adapter",
"yazi-codegen",
"yazi-config", "yazi-config",
"yazi-fs", "yazi-fs",
"yazi-macro", "yazi-macro",

View file

@ -50,7 +50,7 @@ percent-encoding = "2.3.2"
rand = { version = "0.9.2", default-features = false, features = [ "os_rng", "small_rng", "std" ] } rand = { version = "0.9.2", default-features = false, features = [ "os_rng", "small_rng", "std" ] }
ratatui = { version = "0.30.0", features = [ "serde", "unstable-rendered-line-info", "unstable-widget-ref" ] } ratatui = { version = "0.30.0", features = [ "serde", "unstable-rendered-line-info", "unstable-widget-ref" ] }
regex = "1.12.2" regex = "1.12.2"
russh = { version = "0.56.0", default-features = false, features = [ "ring", "rsa" ] } russh = { version = "0.57.0", default-features = false, features = [ "ring", "rsa" ] }
scopeguard = "1.2.0" scopeguard = "1.2.0"
serde = { version = "1.0.228", features = [ "derive" ] } serde = { version = "1.0.228", features = [ "derive" ] }
serde_json = "1.0.149" serde_json = "1.0.149"
@ -62,7 +62,7 @@ tokio-util = "0.7.18"
toml = { version = "0.9.11" } toml = { version = "0.9.11" }
tracing = { version = "0.1.44", features = [ "max_level_debug", "release_max_level_debug" ] } tracing = { version = "0.1.44", features = [ "max_level_debug", "release_max_level_debug" ] }
twox-hash = { version = "2.1.2", default-features = false, features = [ "std", "random", "xxhash3_128" ] } twox-hash = { version = "2.1.2", default-features = false, features = [ "std", "random", "xxhash3_128" ] }
typed-path = "0.12.0" typed-path = "0.12.1"
unicode-width = { version = "0.2.2", default-features = false } unicode-width = { version = "0.2.2", default-features = false }
uzers = "0.12.2" uzers = "0.12.2"

View file

@ -1,7 +1,7 @@
use std::ops::Deref; use std::ops::Deref;
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields, Value}; use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields, Value};
use yazi_binding::{SER_OPT, cached_field, deprecate}; use yazi_binding::{SER_OPT, cached_field};
use super::{Lives, PtrCell}; use super::{Lives, PtrCell};
use crate::lives::TaskSnap; use crate::lives::TaskSnap;
@ -9,9 +9,8 @@ use crate::lives::TaskSnap;
pub(super) struct Tasks { pub(super) struct Tasks {
inner: PtrCell<yazi_core::tasks::Tasks>, inner: PtrCell<yazi_core::tasks::Tasks>,
v_snaps: Option<Value>, v_snaps: Option<Value>,
v_summary: Option<Value>, v_summary: Option<Value>,
v_progress: Option<Value>,
} }
impl Deref for Tasks { impl Deref for Tasks {
@ -25,9 +24,8 @@ impl Tasks {
Lives::scoped_userdata(Self { Lives::scoped_userdata(Self {
inner: inner.into(), inner: inner.into(),
v_snaps: None, v_snaps: None,
v_summary: None, v_summary: None,
v_progress: None,
}) })
} }
} }
@ -45,19 +43,5 @@ impl UserData for Tasks {
}); });
cached_field!(fields, summary, |lua, me| lua.to_value_with(&me.summary, SER_OPT)); cached_field!(fields, summary, |lua, me| lua.to_value_with(&me.summary, SER_OPT));
cached_field!(fields, progress, |lua, me| {
deprecate!(
lua,
"`cx.tasks.progress` is deprecated, use `cx.tasks.summary` instead, in your {}"
);
lua.create_table_from([
("total", me.summary.total),
("succ", me.summary.success),
("fail", me.summary.failed),
("found", 0),
("processed", 0),
])
});
} }
} }

View file

@ -1,7 +1,9 @@
use anyhow::Result; use anyhow::Result;
use yazi_core::which::WhichSorter;
use yazi_dds::spark::SparkKind;
use yazi_macro::{render, succ}; use yazi_macro::{render, succ};
use yazi_parser::which::ShowOpt; use yazi_parser::which::ShowOpt;
use yazi_shared::data::Data; use yazi_shared::{Source, data::Data};
use crate::{Actor, Ctx}; use crate::{Actor, Ctx};
@ -12,17 +14,27 @@ impl Actor for Show {
const NAME: &str = "show"; const NAME: &str = "show";
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> { fn act(cx: &mut Ctx, mut opt: Self::Options) -> Result<Data> {
opt.cands.retain(|c| c.on.len() > opt.times);
WhichSorter::default().sort(&mut opt.cands);
if opt.cands.is_empty() { if opt.cands.is_empty() {
succ!(); succ!();
} }
let which = &mut cx.which; let which = &mut cx.which;
which.times = 0; which.times = opt.times;
which.cands = opt.cands.into_iter().map(|c| c.into()).collect(); which.cands = opt.cands;
which.visible = true; which.visible = true;
which.silent = opt.silent; which.silent = opt.silent;
succ!(render!()); succ!(render!());
} }
fn hook(cx: &Ctx, _opt: &Self::Options) -> Option<SparkKind> {
match cx.source() {
Source::Unknown => Some(SparkKind::IndWhichShow),
_ => None,
}
}
} }

View file

@ -17,6 +17,7 @@ vendored-lua = [ "mlua/vendored" ]
[dependencies] [dependencies]
yazi-adapter = { path = "../yazi-adapter", version = "26.1.22" } yazi-adapter = { path = "../yazi-adapter", version = "26.1.22" }
yazi-codegen = { path = "../yazi-codegen", version = "26.1.22" }
yazi-config = { path = "../yazi-config", version = "26.1.22" } yazi-config = { path = "../yazi-config", version = "26.1.22" }
yazi-fs = { path = "../yazi-fs", version = "26.1.22" } yazi-fs = { path = "../yazi-fs", version = "26.1.22" }
yazi-macro = { path = "../yazi-macro", version = "26.1.22" } yazi-macro = { path = "../yazi-macro", version = "26.1.22" }

View file

@ -0,0 +1,11 @@
use mlua::UserData;
use yazi_codegen::FromLuaOwned;
#[derive(FromLuaOwned)]
pub struct ChordCow(pub yazi_config::keymap::ChordCow);
impl From<ChordCow> for yazi_config::keymap::ChordCow {
fn from(value: ChordCow) -> Self { value.0 }
}
impl UserData for ChordCow {}

View file

@ -3,7 +3,6 @@ use std::ops::Deref;
use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value}; use mlua::{FromLua, IntoLua, Lua, MetaMethod, Table, UserData, Value};
use super::Pad; use super::Pad;
use crate::deprecate;
#[derive(Clone, Copy, Debug, Default, FromLua)] #[derive(Clone, Copy, Debug, Default, FromLua)]
pub struct Rect(pub ratatui::layout::Rect); pub struct Rect(pub ratatui::layout::Rect);
@ -35,20 +34,8 @@ impl Rect {
})) }))
})?; })?;
let index = lua.create_function(move |lua, (_, key): (Table, mlua::String)| {
Ok(match &*key.as_bytes() {
b"default" => {
deprecate!(lua, "`ui.Rect.default` is deprecated, use `ui.Rect{{}}` instead, in your {}\nSee #2927 for more details: https://github.com/sxyazi/yazi/pull/2927");
Some(Self(Default::default()))
}
_ => None,
})
})?;
let rect = lua.create_table()?; let rect = lua.create_table()?;
rect.set_metatable(Some( rect.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?))?;
lua.create_table_from([(MetaMethod::Call.name(), new), (MetaMethod::Index.name(), index)])?,
))?;
rect.into_lua(lua) rect.into_lua(lua)
} }

View file

@ -1,10 +1,10 @@
use std::{borrow::Cow, fmt::Display}; use std::{borrow::Cow, fmt::Display};
use mlua::{ExternalError, FromLua, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, Value}; use mlua::{ExternalError, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, Value};
use yazi_codegen::FromLuaOwned;
use yazi_shared::SStr; use yazi_shared::SStr;
const EXPECTED: &str = "expected a Error"; #[derive(FromLuaOwned)]
pub enum Error { pub enum Error {
Io(std::io::Error), Io(std::io::Error),
Fs(yazi_fs::error::Error), Fs(yazi_fs::error::Error),
@ -53,15 +53,6 @@ impl Display for Error {
} }
} }
impl FromLua for Error {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
match value {
Value::UserData(ud) => ud.take(),
_ => Err(EXPECTED.into_lua_err()),
}
}
}
impl UserData for Error { impl UserData for Error {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) { fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("code", |_, me| { fields.add_field_method_get("code", |_, me| {

View file

@ -1,6 +1,7 @@
use std::ops::Deref; use std::ops::Deref;
use mlua::{AnyUserData, ExternalError, FromLua, Lua, ObjectLike, Table, UserData, UserDataFields, UserDataMethods, UserDataRef, Value}; use mlua::{AnyUserData, ExternalError, Lua, ObjectLike, Table, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
use yazi_codegen::FromLuaOwned;
use crate::{Cha, Url, impl_file_fields, impl_file_methods}; use crate::{Cha, Url, impl_file_fields, impl_file_methods};
@ -8,7 +9,7 @@ pub type FileRef = UserDataRef<File>;
const EXPECTED: &str = "expected a table, File, or fs::File"; const EXPECTED: &str = "expected a table, File, or fs::File";
#[derive(Clone)] #[derive(Clone, FromLuaOwned)]
pub struct File { pub struct File {
inner: yazi_fs::File, inner: yazi_fs::File,
@ -82,15 +83,6 @@ impl TryFrom<AnyUserData> for File {
} }
} }
impl FromLua for File {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(match value {
Value::UserData(ud) => Self::new(ud.take::<Self>()?.inner),
_ => Err("expected a File".into_lua_err())?,
})
}
}
impl UserData for File { impl UserData for File {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) { fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
impl_file_fields!(fields); impl_file_fields!(fields);

View file

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

View file

@ -1,12 +1,14 @@
use std::ops::Deref; use std::ops::Deref;
use mlua::{ExternalError, ExternalResult, FromLua, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value}; use mlua::{ExternalError, ExternalResult, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
use yazi_codegen::FromLuaOwned;
use yazi_shared::{path::{PathBufDyn, PathLike, StripPrefixError}, strand::{AsStrand, Strand, StrandCow}}; use yazi_shared::{path::{PathBufDyn, PathLike, StripPrefixError}, strand::{AsStrand, Strand, StrandCow}};
use crate::cached_field; use crate::cached_field;
pub type PathRef = UserDataRef<Path>; pub type PathRef = UserDataRef<Path>;
#[derive(FromLuaOwned)]
pub struct Path { pub struct Path {
inner: PathBufDyn, inner: PathBufDyn,
@ -106,15 +108,6 @@ impl Path {
} }
} }
impl FromLua for Path {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(match value {
Value::UserData(ud) => ud.take()?,
_ => Err("Expected a Path".into_lua_err())?,
})
}
}
impl UserData for Path { impl UserData for Path {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) { fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
cached_field!(fields, ext, |lua, me| { cached_field!(fields, ext, |lua, me| {

View file

@ -1,15 +1,17 @@
use std::ops::Deref; use std::ops::Deref;
use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value}; use mlua::{AnyUserData, ExternalError, ExternalResult, IntoLua, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
use yazi_codegen::FromLuaOwned;
use yazi_fs::{FsHash64, FsHash128, FsUrl}; use yazi_fs::{FsHash64, FsHash128, FsUrl};
use yazi_shared::{path::{PathLike, StripPrefixError}, scheme::{SchemeCow, SchemeLike}, strand::{StrandLike, ToStrand}, url::{AsUrl, UrlCow, UrlLike}}; use yazi_shared::{path::{PathLike, StripPrefixError}, scheme::{SchemeCow, SchemeLike}, strand::{StrandLike, ToStrand}, url::{AsUrl, UrlCow, UrlLike}};
use crate::{Path, Scheme, cached_field, deprecate}; use crate::{Path, Scheme, cached_field};
pub type UrlRef = UserDataRef<Url>; pub type UrlRef = UserDataRef<Url>;
const EXPECTED: &str = "expected a string, Url, or Path"; const EXPECTED: &str = "expected a string, Url, or Path";
#[derive(FromLuaOwned)]
pub struct Url { pub struct Url {
inner: yazi_shared::url::UrlBuf, inner: yazi_shared::url::UrlBuf,
@ -162,15 +164,6 @@ impl Url {
} }
} }
impl FromLua for Url {
fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
Ok(match value {
Value::UserData(ud) => ud.take()?,
_ => Err("Expected a Url".into_lua_err())?,
})
}
}
impl UserData for Url { impl UserData for Url {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) { fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
cached_field!(fields, path, |_, me| Ok(Path::new(me.loc()))); cached_field!(fields, path, |_, me| Ok(Path::new(me.loc())));
@ -196,11 +189,6 @@ impl UserData for Url {
cached_field!(fields, cache, |_, me| Ok(me.cache().map(Path::new))); cached_field!(fields, cache, |_, me| Ok(me.cache().map(Path::new)));
fields.add_field_method_get("frag", |lua, me| {
deprecate!(lua, "`frag` property of Url is deprecated and renamed to `domain`, please use the new name instead, in your {}");
me.scheme().domain().map(|s| lua.create_string(s)).transpose()
});
fields.add_field_method_get("is_regular", |_, me| Ok(me.is_regular())); fields.add_field_method_get("is_regular", |_, me| Ok(me.is_regular()));
fields.add_field_method_get("is_search", |_, me| Ok(me.is_search())); fields.add_field_method_get("is_search", |_, me| Ok(me.is_search()));
fields.add_field_method_get("is_archive", |_, me| Ok(me.is_archive())); fields.add_field_method_get("is_archive", |_, me| Ok(me.is_archive()));

View file

@ -17,4 +17,4 @@ proc-macro = true
[dependencies] [dependencies]
# External dependencies # External dependencies
syn = { version = "2.0.114", features = [ "full" ] } syn = { version = "2.0.114", features = [ "full" ] }
quote = "1.0.43" quote = "1.0.44"

View file

@ -144,3 +144,28 @@ pub fn deserialize_over2(input: TokenStream) -> TokenStream {
} }
.into() .into()
} }
#[proc_macro_derive(FromLuaOwned)]
pub fn from_lua(input: TokenStream) -> TokenStream {
let DeriveInput { ident, generics, .. } = parse_macro_input!(input as DeriveInput);
let ident_str = ident.to_string();
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
quote! {
impl #impl_generics ::mlua::FromLua for #ident #ty_generics #where_clause {
#[inline]
fn from_lua(value: ::mlua::Value, _: &::mlua::Lua) -> ::mlua::Result<Self> {
match value {
::mlua::Value::UserData(ud) => ud.take::<Self>(),
_ => Err(::mlua::Error::FromLuaConversionError {
from: value.type_name(),
to: #ident_str.to_owned(),
message: None,
}),
}
}
}
}
.into()
}

View file

@ -30,14 +30,17 @@ impl Deref for ChordCow {
} }
impl Default for ChordCow { impl Default for ChordCow {
fn default() -> Self { Self::Owned(Chord::default()) } fn default() -> Self {
const C: &Chord = &Chord { on: vec![], run: vec![], desc: None, r#for: None };
Self::Borrowed(C)
}
} }
impl ChordCow { impl ChordCow {
pub fn into_seq(self) -> Vec<CmdCow> { pub fn into_seq(self) -> Vec<CmdCow> {
match self { match self {
Self::Owned(c) => c.run.into_iter().rev().map(|c| c.into()).collect(), Self::Owned(c) => c.run.into_iter().rev().map(Into::into).collect(),
Self::Borrowed(c) => c.run.iter().rev().map(|c| c.into()).collect(), Self::Borrowed(c) => c.run.iter().rev().map(Into::into).collect(),
} }
} }
} }

View file

@ -23,7 +23,7 @@ impl Default for WhichSorter {
} }
impl WhichSorter { impl WhichSorter {
pub(super) fn sort(&self, items: &mut Vec<ChordCow>) { pub fn sort(&self, items: &mut Vec<ChordCow>) {
if self.by == SortBy::None || items.is_empty() { if self.by == SortBy::None || items.is_empty() {
return; return;
} }

View file

@ -1,8 +1,5 @@
use yazi_config::{KEYMAP, keymap::{ChordCow, Key}}; use yazi_config::keymap::{ChordCow, Key};
use yazi_macro::{emit, render, render_and}; use yazi_macro::{emit, render_and};
use yazi_shared::Layer;
use crate::which::WhichSorter;
#[derive(Default)] #[derive(Default)]
pub struct Which { pub struct Which {
@ -39,19 +36,4 @@ impl Which {
self.visible = false; self.visible = false;
self.silent = false; self.silent = false;
} }
pub fn show_with(&mut self, key: Key, layer: Layer) {
self.times = 1;
self.cands = KEYMAP
.get(layer)
.iter()
.filter(|c| c.on.len() > 1 && c.on[0] == key)
.map(|c| c.into())
.collect();
WhichSorter::default().sort(&mut self.cands);
self.visible = true;
self.silent = false;
render!();
}
} }

View file

@ -2,27 +2,31 @@ use std::fmt::Display;
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SparkKind { pub enum SparkKind {
// Sort // sort
KeySort, KeySort,
IndSort, IndSort,
// Stash // stash
IndStash, IndStash,
RelayStash, RelayStash,
// Quit // quit
KeyQuit, KeyQuit,
// which:show
IndWhichShow,
} }
impl AsRef<str> for SparkKind { impl AsRef<str> for SparkKind {
fn as_ref(&self) -> &str { fn as_ref(&self) -> &str {
match self { match self {
// Sort // sort
Self::KeySort => "key-sort", Self::KeySort => "key-sort",
Self::IndSort => "ind-sort", Self::IndSort => "ind-sort",
// Stash // stash
Self::IndStash => "ind-stash", Self::IndStash => "ind-stash",
Self::RelayStash => "relay-stash", Self::RelayStash => "relay-stash",
// Quit // quit
Self::KeyQuit => "key-quit", Self::KeyQuit => "key-quit",
// which:show
Self::IndWhichShow => "ind-which-show",
} }
} }
} }

View file

@ -140,14 +140,16 @@ impl<'a> Spark<'a> {
use SparkKind::*; use SparkKind::*;
Ok(match kind { Ok(match kind {
// Sort // sort
KeySort => Self::Sort(<_>::from_lua(value, lua)?), KeySort => Self::Sort(<_>::from_lua(value, lua)?),
IndSort => Self::Sort(<_>::from_lua(value, lua)?), IndSort => Self::Sort(<_>::from_lua(value, lua)?),
// Stash // stash
IndStash => Self::Stash(<_>::from_lua(value, lua)?), IndStash => Self::Stash(<_>::from_lua(value, lua)?),
RelayStash => Self::Stash(<_>::from_lua(value, lua)?), RelayStash => Self::Stash(<_>::from_lua(value, lua)?),
// Quit // quit
KeyQuit => Self::Quit(<_>::from_lua(value, lua)?), KeyQuit => Self::Quit(<_>::from_lua(value, lua)?),
// which:show
IndWhichShow => Self::WhichShow(<_>::from_lua(value, lua)?),
}) })
} }
} }

View file

@ -1,6 +1,7 @@
use anyhow::Result; use anyhow::Result;
use yazi_actor::Ctx;
use yazi_config::{KEYMAP, keymap::{Chord, ChordCow, Key}}; use yazi_config::{KEYMAP, keymap::{Chord, ChordCow, Key}};
use yazi_macro::emit; use yazi_macro::{act, emit};
use yazi_shared::Layer; use yazi_shared::Layer;
use crate::app::App; use crate::app::App;
@ -41,7 +42,8 @@ impl<'a> Router<'a> {
} }
if on.len() > 1 { if on.len() > 1 {
self.app.core.which.show_with(key, layer); let cx = &mut Ctx::active(&mut self.app.core);
act!(which:show, cx, (layer, key)).ok();
} else { } else {
emit!(Seq(ChordCow::from(chord).into_seq())); emit!(Seq(ChordCow::from(chord).into_seq()));
} }

View file

@ -1,29 +1,68 @@
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; use anyhow::bail;
use yazi_config::keymap::Chord; use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, Value};
use yazi_shared::event::CmdCow; use yazi_config::{KEYMAP, keymap::{ChordCow, Key}};
use yazi_shared::{Layer, event::CmdCow};
#[derive(Debug)] #[derive(Debug)]
pub struct ShowOpt { pub struct ShowOpt {
pub cands: Vec<Chord>, pub cands: Vec<ChordCow>,
pub silent: bool, pub silent: bool,
pub times: usize,
} }
impl TryFrom<CmdCow> for ShowOpt { impl TryFrom<CmdCow> for ShowOpt {
type Error = anyhow::Error; type Error = anyhow::Error;
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> { fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
if let Some(opt) = c.take_any2("opt") { match c.take_any2("opt") {
return opt; Some(opt) => opt,
None => bail!("missing 'opt' argument"),
} }
}
}
Ok(Self { cands: c.take_any("candidates").unwrap_or_default(), silent: c.bool("silent") }) impl From<(Layer, Key)> for ShowOpt {
fn from((layer, key): (Layer, Key)) -> Self {
Self {
cands: KEYMAP
.get(layer)
.iter()
.filter(|c| c.on.len() > 1 && c.on[0] == key)
.map(Into::into)
.collect(),
times: 1,
silent: false,
}
} }
} }
impl FromLua for ShowOpt { impl FromLua for ShowOpt {
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) } fn from_lua(value: Value, _: &Lua) -> mlua::Result<Self> {
let Value::Table(t) = value else {
return Err("expected a table".into_lua_err());
};
Ok(ShowOpt {
cands: t
.raw_get::<Table>("cands")?
.sequence_values::<yazi_binding::ChordCow>()
.map(|c| c.map(Into::into))
.collect::<mlua::Result<Vec<_>>>()?,
times: t.raw_get("times").unwrap_or_default(),
silent: t.raw_get("silent")?,
})
}
} }
impl IntoLua for ShowOpt { impl IntoLua for ShowOpt {
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) } #[rustfmt::skip]
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
lua
.create_table_from([
("cands", lua.create_sequence_from(self.cands.into_iter().map(yazi_binding::ChordCow))?.into_lua(lua)?),
("times", self.times.into_lua(lua)?),
("silent", self.silent.into_lua(lua)?),
])?
.into_lua(lua)
}
} }

View file

@ -1,12 +0,0 @@
local function fetch(_, job)
ya.notify {
title = "Deprecated plugin",
content = "The `mime` fetcher is deprecated, use `mime.local` instead in your `yazi.toml`\n\nSee https://github.com/sxyazi/yazi/pull/3222 for more details.",
timeout = 15,
level = "warn",
}
return require("mime.local"):fetch(job)
end
return { fetch = fetch }

View file

@ -138,7 +138,7 @@ pub(super) fn truncate(lua: &Lua) -> mlua::Result<Value> {
} }
let lossy = String::from_utf8_lossy(&b); let lossy = String::from_utf8_lossy(&b);
let rtl = t.raw_get("rtl").unwrap_or(false); let rtl = t.raw_get("rtl")?;
let (idx, width, remain) = if rtl { let (idx, width, remain) = if rtl {
traverse(lossy.char_indices().rev(), max) traverse(lossy.char_indices().rev(), max)
} else { } else {

View file

@ -134,7 +134,7 @@ fn read_dir(lua: &Lua) -> mlua::Result<Function> {
}; };
let limit = options.raw_get("limit").unwrap_or(usize::MAX); let limit = options.raw_get("limit").unwrap_or(usize::MAX);
let resolve = options.raw_get("resolve").unwrap_or(false); let resolve = options.raw_get::<bool>("resolve")?;
let mut it = match provider::read_dir(&*dir).await { let mut it = match provider::read_dir(&*dir).await {
Ok(it) => it, Ok(it) => it,

View file

@ -38,7 +38,7 @@ impl Default for Loader {
("image".to_owned(), preset!("plugins/image").into()), ("image".to_owned(), preset!("plugins/image").into()),
("json".to_owned(), preset!("plugins/json").into()), ("json".to_owned(), preset!("plugins/json").into()),
("magick".to_owned(), preset!("plugins/magick").into()), ("magick".to_owned(), preset!("plugins/magick").into()),
("mime".to_owned(), preset!("plugins/mime").into()), // TODO: remove this ("mime".to_owned(), preset!("plugins/mime").into()),
("mime.dir".to_owned(), preset!("plugins/mime-dir").into()), ("mime.dir".to_owned(), preset!("plugins/mime-dir").into()),
("mime.local".to_owned(), preset!("plugins/mime-local").into()), ("mime.local".to_owned(), preset!("plugins/mime-local").into()),
("mime.remote".to_owned(), preset!("plugins/mime-remote").into()), ("mime.remote".to_owned(), preset!("plugins/mime-remote").into()),

View file

@ -1,5 +1,5 @@
use mlua::{IntoLua, Lua, Value}; use mlua::{IntoLua, Lua, Value};
use yazi_binding::{Composer, ComposerGet, ComposerSet, Style, Url, deprecate}; use yazi_binding::{Composer, ComposerGet, ComposerSet, Style, Url};
use yazi_config::THEME; use yazi_config::THEME;
pub fn compose() -> Composer<ComposerGet, ComposerSet> { pub fn compose() -> Composer<ComposerGet, ComposerSet> {
@ -51,21 +51,6 @@ fn mgr() -> Composer<ComposerGet, ComposerSet> {
match key { match key {
b"cwd" => Style::from(m.cwd).into_lua(lua), b"cwd" => Style::from(m.cwd).into_lua(lua),
b"hovered" => {
deprecate!(
lua,
"`th.mgr.hovered` is deprecated, use `th.indicator.current` instead, in your {}\nSee #3419 for more details: https://github.com/sxyazi/yazi/pull/3419"
);
Style::from(THEME.indicator.current).into_lua(lua)
}
b"preview_hovered" => {
deprecate!(
lua,
"`th.mgr.preview_hovered` is deprecated, use `th.indicator.preview` instead, in your {}\nSee #3419 for more details: https://github.com/sxyazi/yazi/pull/3419"
);
Style::from(THEME.indicator.preview).into_lua(lua)
}
b"find_keyword" => Style::from(m.find_keyword).into_lua(lua), b"find_keyword" => Style::from(m.find_keyword).into_lua(lua),
b"find_position" => Style::from(m.find_position).into_lua(lua), b"find_position" => Style::from(m.find_position).into_lua(lua),

View file

@ -2,8 +2,7 @@ use std::any::TypeId;
use mlua::{AnyUserData, ExternalError, Function, Lua}; use mlua::{AnyUserData, ExternalError, Function, Lua};
use tokio::process::{ChildStderr, ChildStdin, ChildStdout}; use tokio::process::{ChildStderr, ChildStdin, ChildStdout};
use yazi_binding::{Id, Permit, PermitRef, deprecate}; use yazi_binding::Id;
use yazi_proxy::{AppProxy, HIDER};
use super::Utils; use super::Utils;
@ -30,20 +29,4 @@ impl Utils {
ud.destroy() ud.destroy()
}) })
} }
pub(super) fn hide(lua: &Lua) -> mlua::Result<Function> {
lua.create_async_function(|lua, ()| async move {
deprecate!(lua, "`ya.hide()` is deprecated, use `ui.hide()` instead, in your {}\nSee #2939 for more details: https://github.com/sxyazi/yazi/pull/2939");
if lua.named_registry_value::<PermitRef>("HIDE_PERMIT").is_ok_and(|h| h.is_some()) {
return Err("Cannot hide while already hidden".into_lua_err());
}
let permit = HIDER.acquire().await.unwrap();
AppProxy::stop().await;
lua.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume()))?;
lua.named_registry_value::<AnyUserData>("HIDE_PERMIT")
})
}
} }

View file

@ -1,21 +1,11 @@
use mlua::{Function, Lua, Table}; use mlua::{Function, Lua, Table};
use yazi_binding::deprecate;
use yazi_dds::Sendable; use yazi_dds::Sendable;
use yazi_macro::{emit, render}; use yazi_macro::emit;
use yazi_shared::{Layer, Source, event::Cmd}; use yazi_shared::{Layer, Source, event::Cmd};
use super::Utils; use super::Utils;
impl Utils { impl Utils {
pub(super) fn render(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|lua, ()| {
deprecate!(lua, "`ya.render()` is deprecated, use `ui.render()` instead, in your {}\nSee #2939 for more details: https://github.com/sxyazi/yazi/pull/2939");
render!();
Ok(())
})
}
pub(super) fn emit(lua: &Lua) -> mlua::Result<Function> { pub(super) fn emit(lua: &Lua) -> mlua::Result<Function> {
lua.create_function(|lua, (name, args): (String, Table)| { lua.create_function(|lua, (name, args): (String, Table)| {
let mut cmd = Cmd::new(name, Source::Emit, Some(Layer::Mgr))?; let mut cmd = Cmd::new(name, Source::Emit, Some(Layer::Mgr))?;

View file

@ -3,8 +3,8 @@ use std::{str::FromStr, time::Duration};
use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value}; use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_stream::wrappers::UnboundedReceiverStream;
use yazi_binding::{deprecate, elements::{Line, Pos, Text}, runtime}; use yazi_binding::{elements::{Line, Pos, Text}, runtime};
use yazi_config::{keymap::{Chord, Key}, popup::{ConfirmCfg, InputCfg}}; use yazi_config::{keymap::{Chord, ChordCow, Key}, popup::{ConfirmCfg, InputCfg}};
use yazi_macro::relay; use yazi_macro::relay;
use yazi_parser::which::ShowOpt; use yazi_parser::which::ShowOpt;
use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy, WhichProxy}; use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy, WhichProxy};
@ -27,17 +27,17 @@ impl Utils {
.enumerate() .enumerate()
.map(|(i, cand)| { .map(|(i, cand)| {
let cand = cand?; let cand = cand?;
Ok(Chord { Ok(ChordCow::Owned(Chord {
on: Self::parse_keys(cand.raw_get("on")?)?, on: Self::parse_keys(cand.raw_get("on")?)?,
run: vec![relay!(which:callback, [i]).with_any("tx", tx.clone())], run: vec![relay!(which:callback, [i]).with_any("tx", tx.clone())],
desc: cand.raw_get("desc").ok(), desc: cand.raw_get("desc").ok(),
r#for: None, r#for: None,
}) }))
}) })
.collect::<mlua::Result<_>>()?; .collect::<mlua::Result<_>>()?;
drop(tx); drop(tx);
WhichProxy::show(ShowOpt { cands, silent: t.raw_get("silent").unwrap_or_default() }); WhichProxy::show(ShowOpt { cands, times: 0, silent: t.raw_get("silent")? });
Ok(rx.recv().await.map(|idx| idx + 1)) Ok(rx.recv().await.map(|idx| idx + 1))
}) })
@ -49,21 +49,13 @@ impl Utils {
return Err("Cannot call `ya.input()` while main thread is blocked".into_lua_err()); return Err("Cannot call `ya.input()` while main thread is blocked".into_lua_err());
} }
let mut pos = t.raw_get::<Value>("pos")?; let realtime = t.raw_get("realtime")?;
if pos.is_nil() {
pos = t.raw_get("position")?;
if !pos.is_nil() {
deprecate!(lua, "The `position` property of `ya.input()` is deprecated, use `pos` instead in your {}\nSee #2921 for more details: https://github.com/sxyazi/yazi/pull/2921");
}
}
let realtime = t.raw_get("realtime").unwrap_or_default();
let rx = UnboundedReceiverStream::new(InputProxy::show(InputCfg { let rx = UnboundedReceiverStream::new(InputProxy::show(InputCfg {
title: t.raw_get("title")?, title: t.raw_get("title")?,
value: t.raw_get("value").unwrap_or_default(), value: t.raw_get("value").unwrap_or_default(),
cursor: None, // TODO cursor: None, // TODO
obscure: t.raw_get("obscure").unwrap_or_default(), obscure: t.raw_get("obscure")?,
position: Pos::new_input(pos)?.into(), position: Pos::new_input(t.raw_get("pos")?)?.into(),
realtime, realtime,
completion: false, completion: false,
})); }));

View file

@ -1,7 +1,5 @@
use mlua::{Function, Lua, Table}; use mlua::{Function, Lua};
use twox_hash::XxHash3_128; use twox_hash::XxHash3_128;
use unicode_width::UnicodeWidthChar;
use yazi_binding::deprecate;
use yazi_widgets::CLIPBOARD; use yazi_widgets::CLIPBOARD;
use super::Utils; use super::Utils;
@ -25,66 +23,6 @@ impl Utils {
}) })
} }
pub(super) fn truncate(lua: &Lua) -> mlua::Result<Function> {
fn traverse(
it: impl Iterator<Item = (usize, char)>,
max: usize,
) -> (Option<usize>, usize, bool) {
let (mut adv, mut last) = (0, 0);
let idx = it
.take_while(|&(_, c)| {
(last, adv) = (adv, adv + c.width().unwrap_or(0));
adv <= max
})
.map(|(i, _)| i)
.last();
(idx, last, adv > max)
}
lua.create_function(|lua, (s, t): (mlua::String, Table)| {
deprecate!(lua, "`ya.truncate()` is deprecated, use `ui.truncate()` instead, in your {}\nSee #2939 for more details: https://github.com/sxyazi/yazi/pull/2939");
let b = s.as_bytes();
if b.is_empty() {
return Ok(s);
}
let max = t.raw_get("max")?;
if b.len() <= max {
return Ok(s);
} else if max < 1 {
return lua.create_string("");
}
let lossy = String::from_utf8_lossy(&b);
let rtl = t.raw_get("rtl").unwrap_or(false);
let (idx, width, remain) = if rtl {
traverse(lossy.char_indices().rev(), max)
} else {
traverse(lossy.char_indices(), max)
};
let Some(idx) = idx else { return lua.create_string("") };
if !remain {
return Ok(s);
}
let result: Vec<_> = match (rtl, width == max) {
(false, false) => {
let len = lossy[idx..].chars().next().map_or(0, |c| c.len_utf8());
lossy[..idx + len].bytes().chain("".bytes()).collect()
}
(false, true) => lossy[..idx].bytes().chain("".bytes()).collect(),
(true, false) => "".bytes().chain(lossy[idx..].bytes()).collect(),
(true, true) => {
let len = lossy[idx..].chars().next().map_or(0, |c| c.len_utf8());
"".bytes().chain(lossy[idx + len..].bytes()).collect()
}
};
lua.create_string(result)
})
}
pub(super) fn clipboard(lua: &Lua) -> mlua::Result<Function> { pub(super) fn clipboard(lua: &Lua) -> mlua::Result<Function> {
lua.create_async_function(|lua, text: Option<String>| async move { lua.create_async_function(|lua, text: Option<String>| async move {
if let Some(text) = text { if let Some(text) = text {

View file

@ -11,13 +11,11 @@ pub fn compose(
// App // App
b"id" => Utils::id(lua)?, b"id" => Utils::id(lua)?,
b"drop" => Utils::drop(lua)?, b"drop" => Utils::drop(lua)?,
b"hide" => Utils::hide(lua)?,
// Cache // Cache
b"file_cache" => Utils::file_cache(lua)?, b"file_cache" => Utils::file_cache(lua)?,
// Call // Call
b"render" => Utils::render(lua)?,
b"emit" => Utils::emit(lua)?, b"emit" => Utils::emit(lua)?,
b"mgr_emit" => Utils::mgr_emit(lua)?, b"mgr_emit" => Utils::mgr_emit(lua)?,
@ -65,7 +63,6 @@ pub fn compose(
// Text // Text
b"hash" => Utils::hash(lua)?, b"hash" => Utils::hash(lua)?,
b"quote" => Utils::quote(lua)?, b"quote" => Utils::quote(lua)?,
b"truncate" => Utils::truncate(lua)?,
b"clipboard" => Utils::clipboard(lua)?, b"clipboard" => Utils::clipboard(lua)?,
// Time // Time