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

View file

@ -1,7 +1,7 @@
use std::ops::Deref;
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 crate::lives::TaskSnap;
@ -9,9 +9,8 @@ use crate::lives::TaskSnap;
pub(super) struct Tasks {
inner: PtrCell<yazi_core::tasks::Tasks>,
v_snaps: Option<Value>,
v_summary: Option<Value>,
v_progress: Option<Value>,
v_snaps: Option<Value>,
v_summary: Option<Value>,
}
impl Deref for Tasks {
@ -25,9 +24,8 @@ impl Tasks {
Lives::scoped_userdata(Self {
inner: inner.into(),
v_snaps: None,
v_summary: None,
v_progress: None,
v_snaps: None,
v_summary: 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, 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 yazi_core::which::WhichSorter;
use yazi_dds::spark::SparkKind;
use yazi_macro::{render, succ};
use yazi_parser::which::ShowOpt;
use yazi_shared::data::Data;
use yazi_shared::{Source, data::Data};
use crate::{Actor, Ctx};
@ -12,17 +14,27 @@ impl Actor for 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() {
succ!();
}
let which = &mut cx.which;
which.times = 0;
which.cands = opt.cands.into_iter().map(|c| c.into()).collect();
which.times = opt.times;
which.cands = opt.cands;
which.visible = true;
which.silent = opt.silent;
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]
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-fs = { path = "../yazi-fs", 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 super::Pad;
use crate::deprecate;
#[derive(Clone, Copy, Debug, Default, FromLua)]
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()?;
rect.set_metatable(Some(
lua.create_table_from([(MetaMethod::Call.name(), new), (MetaMethod::Index.name(), index)])?,
))?;
rect.set_metatable(Some(lua.create_table_from([(MetaMethod::Call.name(), new)])?))?;
rect.into_lua(lua)
}

View file

@ -1,10 +1,10 @@
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;
const EXPECTED: &str = "expected a Error";
#[derive(FromLuaOwned)]
pub enum Error {
Io(std::io::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 {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("code", |_, me| {

View file

@ -1,6 +1,7 @@
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};
@ -8,7 +9,7 @@ pub type FileRef = UserDataRef<File>;
const EXPECTED: &str = "expected a table, File, or fs::File";
#[derive(Clone)]
#[derive(Clone, FromLuaOwned)]
pub struct 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 {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
impl_file_fields!(fields);

View file

@ -2,4 +2,4 @@ mod macros;
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 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 crate::cached_field;
pub type PathRef = UserDataRef<Path>;
#[derive(FromLuaOwned)]
pub struct Path {
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 {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
cached_field!(fields, ext, |lua, me| {

View file

@ -1,15 +1,17 @@
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_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>;
const EXPECTED: &str = "expected a string, Url, or Path";
#[derive(FromLuaOwned)]
pub struct Url {
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 {
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
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)));
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_search", |_, me| Ok(me.is_search()));
fields.add_field_method_get("is_archive", |_, me| Ok(me.is_archive()));

View file

@ -17,4 +17,4 @@ proc-macro = true
[dependencies]
# External dependencies
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()
}
#[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 {
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 {
pub fn into_seq(self) -> Vec<CmdCow> {
match self {
Self::Owned(c) => c.run.into_iter().rev().map(|c| c.into()).collect(),
Self::Borrowed(c) => c.run.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(Into::into).collect(),
}
}
}

View file

@ -23,7 +23,7 @@ impl Default for 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() {
return;
}

View file

@ -1,8 +1,5 @@
use yazi_config::{KEYMAP, keymap::{ChordCow, Key}};
use yazi_macro::{emit, render, render_and};
use yazi_shared::Layer;
use crate::which::WhichSorter;
use yazi_config::keymap::{ChordCow, Key};
use yazi_macro::{emit, render_and};
#[derive(Default)]
pub struct Which {
@ -39,19 +36,4 @@ impl Which {
self.visible = 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)]
pub enum SparkKind {
// Sort
// sort
KeySort,
IndSort,
// Stash
// stash
IndStash,
RelayStash,
// Quit
// quit
KeyQuit,
// which:show
IndWhichShow,
}
impl AsRef<str> for SparkKind {
fn as_ref(&self) -> &str {
match self {
// Sort
// sort
Self::KeySort => "key-sort",
Self::IndSort => "ind-sort",
// Stash
// stash
Self::IndStash => "ind-stash",
Self::RelayStash => "relay-stash",
// Quit
// quit
Self::KeyQuit => "key-quit",
// which:show
Self::IndWhichShow => "ind-which-show",
}
}
}

View file

@ -140,14 +140,16 @@ impl<'a> Spark<'a> {
use SparkKind::*;
Ok(match kind {
// Sort
// sort
KeySort => Self::Sort(<_>::from_lua(value, lua)?),
IndSort => Self::Sort(<_>::from_lua(value, lua)?),
// Stash
// stash
IndStash => Self::Stash(<_>::from_lua(value, lua)?),
RelayStash => Self::Stash(<_>::from_lua(value, lua)?),
// Quit
// quit
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 yazi_actor::Ctx;
use yazi_config::{KEYMAP, keymap::{Chord, ChordCow, Key}};
use yazi_macro::emit;
use yazi_macro::{act, emit};
use yazi_shared::Layer;
use crate::app::App;
@ -41,7 +42,8 @@ impl<'a> Router<'a> {
}
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 {
emit!(Seq(ChordCow::from(chord).into_seq()));
}

View file

@ -1,29 +1,68 @@
use mlua::{ExternalError, FromLua, IntoLua, Lua, Value};
use yazi_config::keymap::Chord;
use yazi_shared::event::CmdCow;
use anyhow::bail;
use mlua::{ExternalError, FromLua, IntoLua, Lua, Table, Value};
use yazi_config::{KEYMAP, keymap::{ChordCow, Key}};
use yazi_shared::{Layer, event::CmdCow};
#[derive(Debug)]
pub struct ShowOpt {
pub cands: Vec<Chord>,
pub cands: Vec<ChordCow>,
pub silent: bool,
pub times: usize,
}
impl TryFrom<CmdCow> for ShowOpt {
type Error = anyhow::Error;
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
if let Some(opt) = c.take_any2("opt") {
return opt;
match c.take_any2("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 {
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 {
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 rtl = t.raw_get("rtl").unwrap_or(false);
let rtl = t.raw_get("rtl")?;
let (idx, width, remain) = if rtl {
traverse(lossy.char_indices().rev(), max)
} 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 resolve = options.raw_get("resolve").unwrap_or(false);
let resolve = options.raw_get::<bool>("resolve")?;
let mut it = match provider::read_dir(&*dir).await {
Ok(it) => it,

View file

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

View file

@ -1,5 +1,5 @@
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;
pub fn compose() -> Composer<ComposerGet, ComposerSet> {
@ -51,21 +51,6 @@ fn mgr() -> Composer<ComposerGet, ComposerSet> {
match key {
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_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 tokio::process::{ChildStderr, ChildStdin, ChildStdout};
use yazi_binding::{Id, Permit, PermitRef, deprecate};
use yazi_proxy::{AppProxy, HIDER};
use yazi_binding::Id;
use super::Utils;
@ -30,20 +29,4 @@ impl Utils {
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 yazi_binding::deprecate;
use yazi_dds::Sendable;
use yazi_macro::{emit, render};
use yazi_macro::emit;
use yazi_shared::{Layer, Source, event::Cmd};
use super::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> {
lua.create_function(|lua, (name, args): (String, Table)| {
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 tokio::sync::mpsc;
use tokio_stream::wrappers::UnboundedReceiverStream;
use yazi_binding::{deprecate, elements::{Line, Pos, Text}, runtime};
use yazi_config::{keymap::{Chord, Key}, popup::{ConfirmCfg, InputCfg}};
use yazi_binding::{elements::{Line, Pos, Text}, runtime};
use yazi_config::{keymap::{Chord, ChordCow, Key}, popup::{ConfirmCfg, InputCfg}};
use yazi_macro::relay;
use yazi_parser::which::ShowOpt;
use yazi_proxy::{AppProxy, ConfirmProxy, InputProxy, WhichProxy};
@ -27,17 +27,17 @@ impl Utils {
.enumerate()
.map(|(i, cand)| {
let cand = cand?;
Ok(Chord {
Ok(ChordCow::Owned(Chord {
on: Self::parse_keys(cand.raw_get("on")?)?,
run: vec![relay!(which:callback, [i]).with_any("tx", tx.clone())],
desc: cand.raw_get("desc").ok(),
r#for: None,
})
}))
})
.collect::<mlua::Result<_>>()?;
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))
})
@ -49,21 +49,13 @@ impl Utils {
return Err("Cannot call `ya.input()` while main thread is blocked".into_lua_err());
}
let mut pos = t.raw_get::<Value>("pos")?;
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 realtime = t.raw_get("realtime")?;
let rx = UnboundedReceiverStream::new(InputProxy::show(InputCfg {
title: t.raw_get("title")?,
value: t.raw_get("value").unwrap_or_default(),
cursor: None, // TODO
obscure: t.raw_get("obscure").unwrap_or_default(),
position: Pos::new_input(pos)?.into(),
obscure: t.raw_get("obscure")?,
position: Pos::new_input(t.raw_get("pos")?)?.into(),
realtime,
completion: false,
}));

View file

@ -1,7 +1,5 @@
use mlua::{Function, Lua, Table};
use mlua::{Function, Lua};
use twox_hash::XxHash3_128;
use unicode_width::UnicodeWidthChar;
use yazi_binding::deprecate;
use yazi_widgets::CLIPBOARD;
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> {
lua.create_async_function(|lua, text: Option<String>| async move {
if let Some(text) = text {

View file

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