From 497aa26f755fdb60d7e538a79b933beaa2be2fef Mon Sep 17 00:00:00 2001 From: sxyazi Date: Tue, 5 Mar 2024 00:53:01 +0800 Subject: [PATCH 1/3] feat: add `parse` method to `Line` element --- yazi-plugin/preset/setup.lua | 4 +++- yazi-plugin/src/elements/line.rs | 19 ++++++++++++++++++- yazi-plugin/src/loader.rs | 1 + yazi-plugin/src/opt.rs | 2 +- yazi-plugin/src/process/command.rs | 4 ++++ 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/yazi-plugin/preset/setup.lua b/yazi-plugin/preset/setup.lua index 66597d00..77b2a8a8 100644 --- a/yazi-plugin/preset/setup.lua +++ b/yazi-plugin/preset/setup.lua @@ -3,7 +3,9 @@ package.path = BOOT.plugin_dir .. "/?.yazi/init.lua;" .. package.path local _require = require require = function(name) YAZI_PLUGIN_NAME, YAZI_SYNC_CALLS = name, 0 - return _require(name) + local mod = _require(name) + mod._name = name + return mod end YAZI_SYNC_BLOCKS = {} diff --git a/yazi-plugin/src/elements/line.rs b/yazi-plugin/src/elements/line.rs index 9f41a8ec..37bc43cd 100644 --- a/yazi-plugin/src/elements/line.rs +++ b/yazi-plugin/src/elements/line.rs @@ -1,4 +1,7 @@ -use mlua::{AnyUserData, ExternalError, FromLua, IntoLua, Lua, Table, UserData, UserDataMethods, Value}; +use std::mem; + +use ansi_to_tui::IntoText; +use mlua::{AnyUserData, ExternalError, ExternalResult, FromLua, IntoLua, Lua, Table, UserData, UserDataMethods, Value}; use super::{Span, Style}; @@ -39,7 +42,21 @@ impl Line { Err("expected a table of Spans or Lines".into_lua_err()) })?; + let parse = lua.create_function(|_, code: mlua::String| { + let Some(line) = code.as_bytes().split_inclusive(|&b| b == b'\n').next() else { + return Ok(Line(Default::default())); + }; + + let mut lines = line.into_text().into_lua_err()?.lines; + if lines.is_empty() { + return Ok(Line(Default::default())); + } + + Ok(Line(mem::take(&mut lines[0]))) + })?; + let line = lua.create_table_from([ + ("parse", parse.into_lua(lua)?), // Alignment ("LEFT", LEFT.into_lua(lua)?), ("CENTER", CENTER.into_lua(lua)?), diff --git a/yazi-plugin/src/loader.rs b/yazi-plugin/src/loader.rs index b8d02b1b..3408b418 100644 --- a/yazi-plugin/src/loader.rs +++ b/yazi-plugin/src/loader.rs @@ -60,6 +60,7 @@ impl Loader { None => Err(format!("plugin `{name}` not found").into_lua_err())?, }; + t.raw_set("_name", LUA.create_string(name)?)?; loaded.raw_set(name, t.clone())?; Ok(t) } diff --git a/yazi-plugin/src/opt.rs b/yazi-plugin/src/opt.rs index e7854097..0bc86cc7 100644 --- a/yazi-plugin/src/opt.rs +++ b/yazi-plugin/src/opt.rs @@ -21,7 +21,7 @@ impl TryFrom for Opt { fn try_from(mut c: Cmd) -> Result { let Some(name) = c.take_first().filter(|s| !s.is_empty()) else { - bail!("invalid plugin name"); + bail!("plugin name cannot be empty"); }; let mut data: OptData = c.take_data().unwrap_or_default(); diff --git a/yazi-plugin/src/process/command.rs b/yazi-plugin/src/process/command.rs index 33a65ce4..3b67fa5e 100644 --- a/yazi-plugin/src/process/command.rs +++ b/yazi-plugin/src/process/command.rs @@ -49,6 +49,10 @@ impl UserData for Command { } Ok(ud) }); + methods.add_function("cwd", |_, (ud, dir): (AnyUserData, mlua::String)| { + ud.borrow_mut::()?.inner.current_dir(dir.to_str()?); + Ok(ud) + }); methods.add_function( "env", |_, (ud, key, value): (AnyUserData, mlua::String, mlua::String)| { From 37acd94345f910040e6233f840765f6494686609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Tue, 5 Mar 2024 16:46:12 +0800 Subject: [PATCH 2/3] feat: `ya.notify()` plugin API (#780) --- Cargo.lock | 152 +++++++++++++--------- yazi-core/src/input/commands/show.rs | 2 +- yazi-core/src/manager/commands/open.rs | 2 +- yazi-core/src/notify/commands/push.rs | 6 +- yazi-core/src/notify/level.rs | 20 --- yazi-core/src/notify/message.rs | 34 ++--- yazi-core/src/notify/mod.rs | 2 - yazi-core/src/select/commands/show.rs | 2 +- yazi-core/src/tab/commands/escape.rs | 2 +- yazi-core/src/tab/commands/select.rs | 5 +- yazi-core/src/tab/commands/select_all.rs | 5 +- yazi-core/src/tasks/commands/open_with.rs | 2 +- yazi-fm/src/app/commands/notify.rs | 10 +- yazi-fm/src/notify/layout.rs | 9 +- yazi-plugin/src/utils/layer.rs | 10 +- yazi-proxy/Cargo.toml | 1 + yazi-proxy/src/app.rs | 21 ++- yazi-proxy/src/input.rs | 11 +- yazi-proxy/src/lib.rs | 1 + yazi-proxy/src/manager.rs | 11 +- yazi-proxy/src/options/input.rs | 14 ++ yazi-proxy/src/options/mod.rs | 9 ++ yazi-proxy/src/options/notify.rs | 63 +++++++++ yazi-proxy/src/options/open.rs | 26 ++++ yazi-proxy/src/options/select.rs | 14 ++ yazi-proxy/src/select.rs | 11 +- yazi-proxy/src/tasks.rs | 13 +- 27 files changed, 286 insertions(+), 172 deletions(-) delete mode 100644 yazi-core/src/notify/level.rs create mode 100644 yazi-proxy/src/options/input.rs create mode 100644 yazi-proxy/src/options/mod.rs create mode 100644 yazi-proxy/src/options/notify.rs create mode 100644 yazi-proxy/src/options/open.rs create mode 100644 yazi-proxy/src/options/select.rs diff --git a/Cargo.lock b/Cargo.lock index c1dd3431..28030fd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -126,9 +126,9 @@ checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "arc-swap" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" +checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f" [[package]] name = "async-priority-channel" @@ -166,6 +166,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "better-panic" version = "0.3.0" @@ -263,9 +269,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" [[package]] name = "cfg-if" @@ -304,7 +310,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.0", ] [[package]] @@ -502,6 +508,41 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.52", +] + +[[package]] +name = "darling_macro" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.52", +] + [[package]] name = "deranged" version = "0.3.11" @@ -887,14 +928,10 @@ dependencies = [ ] [[package]] -name = "idna" -version = "0.4.0" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" @@ -906,12 +943,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "if_chain" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" - [[package]] name = "image" version = "0.24.9" @@ -998,9 +1029,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1165,9 +1196,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -1431,7 +1462,7 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" dependencies = [ - "base64", + "base64 0.21.7", "indexmap", "line-wrap", "quick-xml", @@ -1592,9 +1623,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -1840,6 +1871,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.0" @@ -2240,7 +2277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", ] @@ -2262,12 +2299,12 @@ dependencies = [ [[package]] name = "validator" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b92f40481c04ff1f4f61f304d61793c7b56ff76ac1469f1beb199b1445b253bd" +checksum = "da339118f018cc70ebf01fafc103360528aad53717e4bf311db929cb01cb9345" dependencies = [ - "idna 0.4.0", - "lazy_static", + "idna", + "once_cell", "regex", "serde", "serde_derive", @@ -2278,28 +2315,16 @@ dependencies = [ [[package]] name = "validator_derive" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc44ca3088bb3ba384d9aecf40c6a23a676ce23e09bdaca2073d99c207f864af" +checksum = "76e88ea23b8f5e59230bff8a2f03c0ee0054a61d5b8343a38946bcd406fe624c" dependencies = [ - "if_chain", - "lazy_static", + "darling", "proc-macro-error", "proc-macro2", "quote", "regex", - "syn 1.0.109", - "validator_types", -] - -[[package]] -name = "validator_types" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "111abfe30072511849c5910134e8baf8dc05de4c0e5903d681cbd5c9c4d611e3" -dependencies = [ - "proc-macro2", - "syn 1.0.109", + "syn 2.0.52", ] [[package]] @@ -2328,9 +2353,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2344,9 +2369,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2354,9 +2379,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", @@ -2369,9 +2394,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2379,9 +2404,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", @@ -2392,9 +2417,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.91" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "weezl" @@ -2668,7 +2693,7 @@ version = "0.2.3" dependencies = [ "anyhow", "arc-swap", - "base64", + "base64 0.22.0", "color_quant", "crossterm", "image", @@ -2719,7 +2744,7 @@ name = "yazi-core" version = "0.2.3" dependencies = [ "anyhow", - "base64", + "base64 0.22.0", "bitflags 2.4.2", "clipboard-win", "crossterm", @@ -2818,6 +2843,7 @@ name = "yazi-proxy" version = "0.2.3" dependencies = [ "anyhow", + "mlua", "tokio", "yazi-config", "yazi-shared", @@ -2829,7 +2855,7 @@ version = "0.2.3" dependencies = [ "anyhow", "async-priority-channel", - "base64", + "base64 0.22.0", "crossterm", "futures", "parking_lot", diff --git a/yazi-core/src/input/commands/show.rs b/yazi-core/src/input/commands/show.rs index bc35e16e..7abfcafc 100644 --- a/yazi-core/src/input/commands/show.rs +++ b/yazi-core/src/input/commands/show.rs @@ -1,4 +1,4 @@ -use yazi_proxy::InputOpt; +use yazi_proxy::options::InputOpt; use yazi_shared::render; use crate::input::Input; diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index c62b31ba..e4d1862a 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -4,7 +4,7 @@ use tracing::error; use yazi_boot::ARGS; use yazi_config::{popup::SelectCfg, OPEN}; use yazi_plugin::isolate; -use yazi_proxy::{ManagerProxy, OpenDoOpt, TasksProxy}; +use yazi_proxy::{options::OpenDoOpt, ManagerProxy, TasksProxy}; use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, MIME_DIR}; use crate::{folder::Folder, manager::Manager, tasks::Tasks}; diff --git a/yazi-core/src/notify/commands/push.rs b/yazi-core/src/notify/commands/push.rs index f3f2572b..0851895f 100644 --- a/yazi-core/src/notify/commands/push.rs +++ b/yazi-core/src/notify/commands/push.rs @@ -5,10 +5,8 @@ use yazi_shared::{emit, event::Cmd, Layer}; use crate::notify::{Message, Notify}; impl Notify { - pub fn push(&mut self, msg: impl TryInto) { - let Ok(mut msg) = msg.try_into() else { - return; - }; + pub fn push(&mut self, msg: impl Into) { + let mut msg = msg.into() as Message; let instant = Instant::now(); msg.timeout += instant - self.messages.first().map_or(instant, |m| m.instant); diff --git a/yazi-core/src/notify/level.rs b/yazi-core/src/notify/level.rs deleted file mode 100644 index f1cfa946..00000000 --- a/yazi-core/src/notify/level.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::str::FromStr; - -pub enum Level { - Info, - Warn, - Error, -} - -impl FromStr for Level { - type Err = (); - - fn from_str(s: &str) -> Result { - Ok(match s { - "info" => Self::Info, - "warn" => Self::Warn, - "error" => Self::Error, - _ => return Err(()), - }) - } -} diff --git a/yazi-core/src/notify/message.rs b/yazi-core/src/notify/message.rs index 9faad177..da80c186 100644 --- a/yazi-core/src/notify/message.rs +++ b/yazi-core/src/notify/message.rs @@ -1,41 +1,31 @@ use std::time::{Duration, Instant}; use unicode_width::UnicodeWidthStr; -use yazi_shared::event::Cmd; +use yazi_proxy::options::{NotifyLevel, NotifyOpt}; -use super::{Level, NOTIFY_BORDER}; +use super::NOTIFY_BORDER; pub struct Message { pub title: String, pub content: String, - pub level: Level, - - pub instant: Instant, + pub level: NotifyLevel, pub timeout: Duration, + pub instant: Instant, pub percent: u8, } -impl TryFrom for Message { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { - let timeout = c.take_name("timeout").and_then(|s| s.parse::().ok()).ok_or(())?; - if timeout < 0.0 { - return Err(()); - } - - let content = c.take_name("content").ok_or(())?; - Ok(Self { - title: c.take_name("title").ok_or(())?, - content, - level: c.take_name("level").ok_or(())?.parse()?, +impl From for Message { + fn from(opt: NotifyOpt) -> Self { + Self { + title: opt.title, + content: opt.content, + level: opt.level, + timeout: opt.timeout, instant: Instant::now(), - timeout: Duration::from_secs_f64(timeout), - percent: 0, - }) + } } } diff --git a/yazi-core/src/notify/mod.rs b/yazi-core/src/notify/mod.rs index f54c7704..3d7d03fc 100644 --- a/yazi-core/src/notify/mod.rs +++ b/yazi-core/src/notify/mod.rs @@ -1,9 +1,7 @@ mod commands; -mod level; mod message; mod notify; -pub use level::*; pub use message::*; pub use notify::*; diff --git a/yazi-core/src/select/commands/show.rs b/yazi-core/src/select/commands/show.rs index b43157e1..1b6d6d1f 100644 --- a/yazi-core/src/select/commands/show.rs +++ b/yazi-core/src/select/commands/show.rs @@ -1,4 +1,4 @@ -use yazi_proxy::SelectOpt; +use yazi_proxy::options::SelectOpt; use yazi_shared::render; use crate::select::Select; diff --git a/yazi-core/src/tab/commands/escape.rs b/yazi-core/src/tab/commands/escape.rs index f730e79c..10015872 100644 --- a/yazi-core/src/tab/commands/escape.rs +++ b/yazi-core/src/tab/commands/escape.rs @@ -112,7 +112,7 @@ impl Tab { if !select { self.selected.remove_many(&urls, same); } else if self.selected.add_many(&urls, same) != urls.len() { - AppProxy::warn( + AppProxy::notify_warn( "Escape visual mode", "Some files cannot be selected, due to path nesting conflict.", ); diff --git a/yazi-core/src/tab/commands/select.rs b/yazi-core/src/tab/commands/select.rs index 78fef324..10a9d987 100644 --- a/yazi-core/src/tab/commands/select.rs +++ b/yazi-core/src/tab/commands/select.rs @@ -38,7 +38,10 @@ impl<'a> Tab { }; if !b { - AppProxy::warn("Select one", "This file cannot be selected, due to path nesting conflict."); + AppProxy::notify_warn( + "Select one", + "This file cannot be selected, due to path nesting conflict.", + ); } } } diff --git a/yazi-core/src/tab/commands/select_all.rs b/yazi-core/src/tab/commands/select_all.rs index 99167e3b..7e7399ae 100644 --- a/yazi-core/src/tab/commands/select_all.rs +++ b/yazi-core/src/tab/commands/select_all.rs @@ -38,7 +38,10 @@ impl Tab { render!(added > 0); if added != addition.len() { - AppProxy::warn("Select all", "Some files cannot be selected, due to path nesting conflict."); + AppProxy::notify_warn( + "Select all", + "Some files cannot be selected, due to path nesting conflict.", + ); } } } diff --git a/yazi-core/src/tasks/commands/open_with.rs b/yazi-core/src/tasks/commands/open_with.rs index cbf247fd..ff874532 100644 --- a/yazi-core/src/tasks/commands/open_with.rs +++ b/yazi-core/src/tasks/commands/open_with.rs @@ -1,4 +1,4 @@ -use yazi_proxy::OpenWithOpt; +use yazi_proxy::options::OpenWithOpt; use crate::tasks::Tasks; diff --git a/yazi-fm/src/app/commands/notify.rs b/yazi-fm/src/app/commands/notify.rs index 2222fb76..ab66ec69 100644 --- a/yazi-fm/src/app/commands/notify.rs +++ b/yazi-fm/src/app/commands/notify.rs @@ -1,7 +1,13 @@ -use yazi_core::notify::Message; +use yazi_proxy::options::NotifyOpt; use crate::app::App; impl App { - pub(crate) fn notify(&mut self, msg: impl TryInto) { self.cx.notify.push(msg); } + pub(crate) fn notify(&mut self, opt: impl TryInto) { + let Ok(opt) = opt.try_into() else { + return; + }; + + self.cx.notify.push(opt); + } } diff --git a/yazi-fm/src/notify/layout.rs b/yazi-fm/src/notify/layout.rs index a0bae27b..39fbea87 100644 --- a/yazi-fm/src/notify/layout.rs +++ b/yazi-fm/src/notify/layout.rs @@ -2,7 +2,8 @@ use std::rc::Rc; use ratatui::{buffer::Buffer, layout::{self, Constraint, Offset, Rect}, widgets::{Block, BorderType, Paragraph, Widget, Wrap}}; use yazi_config::THEME; -use yazi_core::notify::{Level, Message}; +use yazi_core::notify::Message; +use yazi_proxy::options::NotifyLevel; use crate::{widgets::Clear, Ctx}; @@ -43,9 +44,9 @@ impl<'a> Widget for Layout<'a> { for (i, m) in notify.messages.iter().enumerate().take(limit) { let (icon, style) = match m.level { - Level::Info => (&THEME.notify.icon_info, THEME.notify.title_info), - Level::Warn => (&THEME.notify.icon_warn, THEME.notify.title_warn), - Level::Error => (&THEME.notify.icon_error, THEME.notify.title_error), + NotifyLevel::Info => (&THEME.notify.icon_info, THEME.notify.title_info), + NotifyLevel::Warn => (&THEME.notify.icon_warn, THEME.notify.title_warn), + NotifyLevel::Error => (&THEME.notify.icon_error, THEME.notify.title_error), }; let mut rect = diff --git a/yazi-plugin/src/utils/layer.rs b/yazi-plugin/src/utils/layer.rs index c84f5d6a..90bff80a 100644 --- a/yazi-plugin/src/utils/layer.rs +++ b/yazi-plugin/src/utils/layer.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use mlua::{ExternalError, ExternalResult, IntoLuaMulti, Lua, Table, Value}; use tokio::sync::mpsc; use yazi_config::{keymap::{Control, Key}, popup::InputCfg}; -use yazi_proxy::InputProxy; +use yazi_proxy::{AppProxy, InputProxy}; use yazi_shared::{emit, event::Cmd, Layer}; use super::Utils; @@ -79,6 +79,14 @@ impl Utils { })?, )?; + ya.raw_set( + "notify", + lua.create_function(|_, t: Table| { + AppProxy::notify(t.try_into()?); + Ok(()) + })?, + )?; + Ok(()) } } diff --git a/yazi-proxy/Cargo.toml b/yazi-proxy/Cargo.toml index fa1211ca..8fbc3400 100644 --- a/yazi-proxy/Cargo.toml +++ b/yazi-proxy/Cargo.toml @@ -14,4 +14,5 @@ yazi-shared = { path = "../yazi-shared", version = "0.2.3" } # External dependencies anyhow = "^1" +mlua = { version = "^0", features = [ "lua54", "vendored" ] } tokio = { version = "^1", features = [ "parking_lot" ] } diff --git a/yazi-proxy/src/app.rs b/yazi-proxy/src/app.rs index dd5ac3d7..144b66d1 100644 --- a/yazi-proxy/src/app.rs +++ b/yazi-proxy/src/app.rs @@ -1,6 +1,10 @@ +use std::time::Duration; + use tokio::sync::oneshot; use yazi_shared::{emit, event::Cmd, Layer}; +use crate::options::{NotifyLevel, NotifyOpt}; + pub struct AppProxy; impl AppProxy { @@ -16,14 +20,19 @@ impl AppProxy { emit!(Call(Cmd::new("resume"), Layer::App)); } + pub fn notify(opt: NotifyOpt) { + emit!(Call(Cmd::new("notify").with_data(opt), Layer::App)); + } + #[inline] - pub fn warn(title: &str, content: &str) { + pub fn notify_warn(title: &str, content: &str) { emit!(Call( - Cmd::new("notify") - .with("title", title) - .with("content", content) - .with("level", "warn") - .with("timeout", 5), + Cmd::new("notify").with_data(NotifyOpt { + title: title.to_owned(), + content: content.to_owned(), + level: NotifyLevel::Warn, + timeout: Duration::from_secs(5), + }), Layer::App )); } diff --git a/yazi-proxy/src/input.rs b/yazi-proxy/src/input.rs index 5a92b452..66a7491d 100644 --- a/yazi-proxy/src/input.rs +++ b/yazi-proxy/src/input.rs @@ -2,16 +2,7 @@ use tokio::sync::mpsc; use yazi_config::popup::InputCfg; use yazi_shared::{emit, event::Cmd, InputError, Layer}; -pub struct InputOpt { - pub cfg: InputCfg, - pub tx: mpsc::UnboundedSender>, -} - -impl TryFrom for InputOpt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} +use crate::options::InputOpt; pub struct InputProxy; diff --git a/yazi-proxy/src/lib.rs b/yazi-proxy/src/lib.rs index 79993c29..8d60381d 100644 --- a/yazi-proxy/src/lib.rs +++ b/yazi-proxy/src/lib.rs @@ -2,6 +2,7 @@ mod app; mod completion; mod input; mod manager; +pub mod options; mod select; mod tab; mod tasks; diff --git a/yazi-proxy/src/manager.rs b/yazi-proxy/src/manager.rs index 8aa0f561..f690ed6a 100644 --- a/yazi-proxy/src/manager.rs +++ b/yazi-proxy/src/manager.rs @@ -1,15 +1,6 @@ use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; -#[derive(Default)] -pub struct OpenDoOpt { - pub hovered: Url, - pub targets: Vec<(Url, String)>, - pub interactive: bool, -} - -impl From for OpenDoOpt { - fn from(mut c: Cmd) -> Self { c.take_data().unwrap_or_default() } -} +use crate::options::OpenDoOpt; pub struct ManagerProxy; diff --git a/yazi-proxy/src/options/input.rs b/yazi-proxy/src/options/input.rs new file mode 100644 index 00000000..b524a33c --- /dev/null +++ b/yazi-proxy/src/options/input.rs @@ -0,0 +1,14 @@ +use tokio::sync::mpsc; +use yazi_config::popup::InputCfg; +use yazi_shared::{event::Cmd, InputError}; + +pub struct InputOpt { + pub cfg: InputCfg, + pub tx: mpsc::UnboundedSender>, +} + +impl TryFrom for InputOpt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } +} diff --git a/yazi-proxy/src/options/mod.rs b/yazi-proxy/src/options/mod.rs new file mode 100644 index 00000000..e787fc53 --- /dev/null +++ b/yazi-proxy/src/options/mod.rs @@ -0,0 +1,9 @@ +mod input; +mod notify; +mod open; +mod select; + +pub use input::*; +pub use notify::*; +pub use open::*; +pub use select::*; diff --git a/yazi-proxy/src/options/notify.rs b/yazi-proxy/src/options/notify.rs new file mode 100644 index 00000000..a8884d66 --- /dev/null +++ b/yazi-proxy/src/options/notify.rs @@ -0,0 +1,63 @@ +use std::{str::FromStr, time::Duration}; + +use anyhow::bail; +use mlua::{ExternalError, ExternalResult}; +use yazi_shared::event::Cmd; + +pub struct NotifyOpt { + pub title: String, + pub content: String, + pub level: NotifyLevel, + pub timeout: Duration, +} + +impl TryFrom for NotifyOpt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } +} + +impl<'a> TryFrom> for NotifyOpt { + type Error = mlua::Error; + + fn try_from(t: mlua::Table) -> Result { + let timeout = t.raw_get::<_, f64>("timeout")?; + if timeout < 0.0 { + return Err("timeout must be non-negative".into_lua_err()); + } + + let level = if let Ok(s) = t.raw_get::<_, mlua::String>("level") { + s.to_str()?.parse().into_lua_err()? + } else { + Default::default() + }; + + Ok(Self { + title: t.raw_get("title")?, + content: t.raw_get("content")?, + level, + timeout: Duration::from_secs_f64(timeout), + }) + } +} + +#[derive(Default)] +pub enum NotifyLevel { + #[default] + Info, + Warn, + Error, +} + +impl FromStr for NotifyLevel { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(match s { + "info" => Self::Info, + "warn" => Self::Warn, + "error" => Self::Error, + _ => bail!("Invalid notify level: {s}"), + }) + } +} diff --git a/yazi-proxy/src/options/open.rs b/yazi-proxy/src/options/open.rs new file mode 100644 index 00000000..65a6cd5d --- /dev/null +++ b/yazi-proxy/src/options/open.rs @@ -0,0 +1,26 @@ +use yazi_config::open::Opener; +use yazi_shared::{event::Cmd, fs::Url}; + +// --- Open +#[derive(Default)] +pub struct OpenDoOpt { + pub hovered: Url, + pub targets: Vec<(Url, String)>, + pub interactive: bool, +} + +impl From for OpenDoOpt { + fn from(mut c: Cmd) -> Self { c.take_data().unwrap_or_default() } +} + +// --- Open with +pub struct OpenWithOpt { + pub targets: Vec, + pub opener: Opener, +} + +impl TryFrom for OpenWithOpt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } +} diff --git a/yazi-proxy/src/options/select.rs b/yazi-proxy/src/options/select.rs new file mode 100644 index 00000000..0478f4a3 --- /dev/null +++ b/yazi-proxy/src/options/select.rs @@ -0,0 +1,14 @@ +use tokio::sync::oneshot; +use yazi_config::popup::SelectCfg; +use yazi_shared::event::Cmd; + +pub struct SelectOpt { + pub cfg: SelectCfg, + pub tx: oneshot::Sender>, +} + +impl TryFrom for SelectOpt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } +} diff --git a/yazi-proxy/src/select.rs b/yazi-proxy/src/select.rs index 518176dd..5629485d 100644 --- a/yazi-proxy/src/select.rs +++ b/yazi-proxy/src/select.rs @@ -2,16 +2,7 @@ use tokio::sync::oneshot; use yazi_config::popup::SelectCfg; use yazi_shared::{emit, event::Cmd, term::Term, Layer}; -pub struct SelectOpt { - pub cfg: SelectCfg, - pub tx: oneshot::Sender>, -} - -impl TryFrom for SelectOpt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} +use crate::options::SelectOpt; pub struct SelectProxy; diff --git a/yazi-proxy/src/tasks.rs b/yazi-proxy/src/tasks.rs index d60672fc..24ce61f6 100644 --- a/yazi-proxy/src/tasks.rs +++ b/yazi-proxy/src/tasks.rs @@ -1,19 +1,10 @@ use yazi_config::open::Opener; use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; +use crate::options::OpenWithOpt; + pub struct TasksProxy; -pub struct OpenWithOpt { - pub targets: Vec, - pub opener: Opener, -} - -impl TryFrom for OpenWithOpt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} - impl TasksProxy { #[inline] pub fn open_with(targets: Vec, opener: Opener) { From 4e873e62f12fba6a6692960c870e56194608279b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Wed, 6 Mar 2024 19:07:37 +0800 Subject: [PATCH 3/3] feat: `ui.Clear` component for UI plugins (#786) --- yazi-fm/src/app/commands/render.rs | 3 +- yazi-fm/src/completion/completion.rs | 6 +-- yazi-fm/src/help/layout.rs | 4 +- yazi-fm/src/input/input.rs | 4 +- yazi-fm/src/lives/selected.rs | 16 ++++-- yazi-fm/src/main.rs | 1 - yazi-fm/src/notify/layout.rs | 4 +- yazi-fm/src/root.rs | 4 -- yazi-fm/src/select/select.rs | 4 +- yazi-fm/src/tasks/layout.rs | 4 +- yazi-fm/src/which/layout.rs | 4 +- yazi-fm/src/widgets/clear.rs | 43 ---------------- yazi-fm/src/widgets/mod.rs | 3 -- yazi-plugin/src/cast.rs | 12 ++++- yazi-plugin/src/elements/bar.rs | 14 +++--- yazi-plugin/src/elements/border.rs | 26 +++++----- yazi-plugin/src/elements/clear.rs | 75 ++++++++++++++++++++++++++++ yazi-plugin/src/elements/elements.rs | 1 + yazi-plugin/src/elements/layout.rs | 7 +-- yazi-plugin/src/elements/mod.rs | 2 + yazi-plugin/src/elements/rect.rs | 7 +-- yazi-plugin/src/fs/fs.rs | 26 +++++----- yazi-plugin/src/process/child.rs | 18 +++---- yazi-plugin/src/process/command.rs | 24 ++++----- 24 files changed, 173 insertions(+), 139 deletions(-) delete mode 100644 yazi-fm/src/widgets/clear.rs delete mode 100644 yazi-fm/src/widgets/mod.rs create mode 100644 yazi-plugin/src/elements/clear.rs diff --git a/yazi-fm/src/app/commands/render.rs b/yazi-fm/src/app/commands/render.rs index e9106f4c..b2350cff 100644 --- a/yazi-fm/src/app/commands/render.rs +++ b/yazi-fm/src/app/commands/render.rs @@ -1,8 +1,9 @@ use std::sync::atomic::Ordering; use ratatui::{backend::{Backend, CrosstermBackend}, CompletedFrame}; +use yazi_plugin::elements::COLLISION; -use crate::{app::App, lives::Lives, root::{Root, COLLISION}}; +use crate::{app::App, lives::Lives, root::Root}; impl App { pub(crate) fn render(&mut self) { diff --git a/yazi-fm/src/completion/completion.rs b/yazi-fm/src/completion/completion.rs index 05936da1..7dee9d63 100644 --- a/yazi-fm/src/completion/completion.rs +++ b/yazi-fm/src/completion/completion.rs @@ -3,7 +3,7 @@ use std::path::MAIN_SEPARATOR; use ratatui::{buffer::Buffer, layout::Rect, widgets::{Block, BorderType, List, ListItem, Widget}}; use yazi_config::{popup::{Offset, Position}, THEME}; -use crate::{widgets, Ctx}; +use crate::Ctx; pub(crate) struct Completion<'a> { cx: &'a Ctx, @@ -28,7 +28,7 @@ impl<'a> Widget for Completion<'a> { &THEME.completion.icon_file }; - let mut item = ListItem::new(format!(" {} {}", icon, x)); + let mut item = ListItem::new(format!(" {icon} {x}")); if i == self.cx.completion.rel_cursor() { item = item.style(THEME.completion.active); } else { @@ -54,7 +54,7 @@ impl<'a> Widget for Completion<'a> { area.height = rect.height.saturating_sub(area.y).min(area.height); } - widgets::Clear.render(area, buf); + yazi_plugin::elements::Clear::default().render(area, buf); List::new(items) .block( Block::bordered().border_type(BorderType::Rounded).border_style(THEME.completion.border), diff --git a/yazi-fm/src/help/layout.rs b/yazi-fm/src/help/layout.rs index 633b3d67..2bbfdeba 100644 --- a/yazi-fm/src/help/layout.rs +++ b/yazi-fm/src/help/layout.rs @@ -2,7 +2,7 @@ use ratatui::{buffer::Buffer, layout::{self, Constraint, Rect}, text::Line, widg use yazi_config::THEME; use super::Bindings; -use crate::{widgets, Ctx}; +use crate::Ctx; pub(crate) struct Layout<'a> { cx: &'a Ctx, @@ -15,7 +15,7 @@ impl<'a> Layout<'a> { impl<'a> Widget for Layout<'a> { fn render(self, area: Rect, buf: &mut Buffer) { let help = &self.cx.help; - widgets::Clear.render(area, buf); + yazi_plugin::elements::Clear::default().render(area, buf); let chunks = layout::Layout::vertical([Constraint::Fill(1), Constraint::Length(1)]).split(area); Line::styled( diff --git a/yazi-fm/src/input/input.rs b/yazi-fm/src/input/input.rs index f68f7bec..a0863347 100644 --- a/yazi-fm/src/input/input.rs +++ b/yazi-fm/src/input/input.rs @@ -8,7 +8,7 @@ use yazi_core::input::InputMode; use yazi_plugin::external::Highlighter; use yazi_shared::term::Term; -use crate::{widgets, Ctx}; +use crate::Ctx; pub(crate) struct Input<'a> { cx: &'a Ctx, @@ -37,7 +37,7 @@ impl<'a> Widget for Input<'a> { let input = &self.cx.input; let area = self.cx.area(&input.position); - widgets::Clear.render(area, buf); + yazi_plugin::elements::Clear::default().render(area, buf); Paragraph::new(self.highlighted_value().unwrap_or_else(|_| Line::from(input.value()))) .block( Block::bordered() diff --git a/yazi-fm/src/lives/selected.rs b/yazi-fm/src/lives/selected.rs index b20233fb..29fbfb34 100644 --- a/yazi-fm/src/lives/selected.rs +++ b/yazi-fm/src/lives/selected.rs @@ -1,6 +1,6 @@ use std::{collections::{btree_set, BTreeSet}, ops::Deref}; -use mlua::{AnyUserData, Lua, MetaMethod, UserDataMethods, UserDataRefMut}; +use mlua::{AnyUserData, IntoLuaMulti, Lua, MetaMethod, UserDataMethods, UserDataRefMut}; use yazi_plugin::{bindings::Cast, url::Url}; use super::SCOPE; @@ -28,7 +28,12 @@ impl Selected { reg.add_meta_method(MetaMethod::Pairs, |lua, me, ()| { let iter = lua.create_function(|lua, mut iter: UserDataRefMut| { - Ok(if let Some(url) = iter.0.next() { Some(Url::cast(lua, url.clone())?) } else { None }) + if let Some(url) = iter.inner.next() { + iter.next += 1; + (iter.next, Url::cast(lua, url.clone())?).into_lua_multi(lua) + } else { + ().into_lua_multi(lua) + } })?; Ok((iter, SelectedIter::make(me.inner()))) @@ -42,11 +47,14 @@ impl Selected { fn inner(&self) -> &'static BTreeSet { unsafe { &*self.inner } } } -struct SelectedIter(btree_set::Iter<'static, yazi_shared::fs::Url>); +struct SelectedIter { + next: usize, + inner: btree_set::Iter<'static, yazi_shared::fs::Url>, +} impl SelectedIter { #[inline] fn make(selected: &'static BTreeSet) -> mlua::Result> { - SCOPE.create_any_userdata(Self(selected.iter())) + SCOPE.create_any_userdata(Self { next: 0, inner: selected.iter() }) } } diff --git a/yazi-fm/src/main.rs b/yazi-fm/src/main.rs index 380754d7..95b72d1e 100644 --- a/yazi-fm/src/main.rs +++ b/yazi-fm/src/main.rs @@ -22,7 +22,6 @@ mod select; mod signals; mod tasks; mod which; -mod widgets; use context::*; use executor::*; diff --git a/yazi-fm/src/notify/layout.rs b/yazi-fm/src/notify/layout.rs index 39fbea87..33783ef5 100644 --- a/yazi-fm/src/notify/layout.rs +++ b/yazi-fm/src/notify/layout.rs @@ -5,7 +5,7 @@ use yazi_config::THEME; use yazi_core::notify::Message; use yazi_proxy::options::NotifyLevel; -use crate::{widgets::Clear, Ctx}; +use crate::Ctx; pub(crate) struct Layout<'a> { cx: &'a Ctx, @@ -53,7 +53,7 @@ impl<'a> Widget for Layout<'a> { tile[i].offset(Offset { x: (100 - m.percent) as i32 * tile[i].width as i32 / 100, y: 0 }); rect.width = area.width.saturating_sub(rect.x); - Clear.render(rect, buf); + yazi_plugin::elements::Clear::default().render(rect, buf); Paragraph::new(m.content.as_str()) .wrap(Wrap { trim: false }) .block( diff --git a/yazi-fm/src/root.rs b/yazi-fm/src/root.rs index 4b75c623..f5dfdda0 100644 --- a/yazi-fm/src/root.rs +++ b/yazi-fm/src/root.rs @@ -1,12 +1,8 @@ -use std::sync::atomic::AtomicBool; - use ratatui::{buffer::Buffer, layout::{Constraint, Layout, Rect}, widgets::Widget}; use super::{completion, input, select, tasks, which}; use crate::{components, help, Ctx}; -pub(super) static COLLISION: AtomicBool = AtomicBool::new(false); - pub(super) struct Root<'a> { cx: &'a Ctx, } diff --git a/yazi-fm/src/select/select.rs b/yazi-fm/src/select/select.rs index 52eed6e3..9bbf2997 100644 --- a/yazi-fm/src/select/select.rs +++ b/yazi-fm/src/select/select.rs @@ -1,7 +1,7 @@ use ratatui::{buffer::Buffer, layout::Rect, widgets::{Block, BorderType, List, ListItem, Widget}}; use yazi_config::THEME; -use crate::{widgets, Ctx}; +use crate::Ctx; pub(crate) struct Select<'a> { cx: &'a Ctx, @@ -29,7 +29,7 @@ impl<'a> Widget for Select<'a> { }) .collect(); - widgets::Clear.render(area, buf); + yazi_plugin::elements::Clear::default().render(area, buf); List::new(items) .block( Block::bordered() diff --git a/yazi-fm/src/tasks/layout.rs b/yazi-fm/src/tasks/layout.rs index ac1cf6ab..d8785f54 100644 --- a/yazi-fm/src/tasks/layout.rs +++ b/yazi-fm/src/tasks/layout.rs @@ -2,7 +2,7 @@ use ratatui::{buffer::Buffer, layout::{self, Alignment, Constraint, Rect}, text: use yazi_config::THEME; use yazi_core::tasks::TASKS_PERCENT; -use crate::{widgets, Ctx}; +use crate::Ctx; pub(crate) struct Layout<'a> { cx: &'a Ctx, @@ -32,7 +32,7 @@ impl<'a> Widget for Layout<'a> { fn render(self, area: Rect, buf: &mut Buffer) { let area = Self::area(area); - widgets::Clear.render(area, buf); + yazi_plugin::elements::Clear::default().render(area, buf); let block = Block::bordered() .title(Line::styled("Tasks", THEME.tasks.title)) .title_alignment(Alignment::Center) diff --git a/yazi-fm/src/which/layout.rs b/yazi-fm/src/which/layout.rs index 36623ab3..26aed46b 100644 --- a/yazi-fm/src/which/layout.rs +++ b/yazi-fm/src/which/layout.rs @@ -2,7 +2,7 @@ use ratatui::{buffer::Buffer, layout, layout::{Constraint, Rect}, widgets::{Bloc use yazi_config::THEME; use super::Cand; -use crate::{widgets, Ctx}; +use crate::Ctx; const PADDING_X: u16 = 1; const PADDING_Y: u16 = 1; @@ -46,7 +46,7 @@ impl Widget for Which<'_> { .split(area) }; - widgets::Clear.render(area, buf); + yazi_plugin::elements::Clear::default().render(area, buf); Block::new().style(THEME.which.mask).render(area, buf); for y in 0..area.height { diff --git a/yazi-fm/src/widgets/clear.rs b/yazi-fm/src/widgets/clear.rs deleted file mode 100644 index 553d55f1..00000000 --- a/yazi-fm/src/widgets/clear.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::sync::atomic::Ordering; - -use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget}; -use yazi_adaptor::ADAPTOR; - -use crate::root::COLLISION; - -pub(crate) struct Clear; - -#[inline] -const fn is_overlapping(a: &Rect, b: &Rect) -> bool { - a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y -} - -fn overlap(a: &Rect, b: &Rect) -> Option { - if !is_overlapping(a, b) { - return None; - } - - let x = a.x.max(b.x); - let y = a.y.max(b.y); - let width = (a.x + a.width).min(b.x + b.width) - x; - let height = (a.y + a.height).min(b.y + b.height) - y; - Some(Rect { x, y, width, height }) -} - -impl Widget for Clear { - fn render(self, area: Rect, buf: &mut Buffer) { - ratatui::widgets::Clear.render(area, buf); - - let Some(r) = ADAPTOR.shown_load().and_then(|r| overlap(&area, &r)) else { - return; - }; - - ADAPTOR.image_erase(r).ok(); - COLLISION.store(true, Ordering::Relaxed); - for y in area.top()..area.bottom() { - for x in area.left()..area.right() { - buf.get_mut(x, y).set_skip(true); - } - } - } -} diff --git a/yazi-fm/src/widgets/mod.rs b/yazi-fm/src/widgets/mod.rs deleted file mode 100644 index cd6c2c51..00000000 --- a/yazi-fm/src/widgets/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod clear; - -pub(super) use clear::*; diff --git a/yazi-plugin/src/cast.rs b/yazi-plugin/src/cast.rs index d426f3d5..f753fa27 100644 --- a/yazi-plugin/src/cast.rs +++ b/yazi-plugin/src/cast.rs @@ -12,6 +12,8 @@ pub fn cast_to_renderable(ud: AnyUserData) -> Option> Some(Box::new(c)) } else if let Ok(c) = ud.take::() { Some(Box::new(c)) + } else if let Ok(c) = ud.take::() { + Some(Box::new(c)) } else if let Ok(c) = ud.take::() { Some(Box::new(c)) } else if let Ok(c) = ud.take::() { @@ -67,9 +69,10 @@ impl<'lua> IntoLua<'lua> for ValueSendable { ValueSendable::Number(n) => Ok(Value::Number(n)), ValueSendable::String(s) => Ok(Value::String(lua.create_string(s)?)), ValueSendable::Table(t) => { - let table = lua.create_table()?; + let seq_len = t.keys().filter(|&k| !k.is_numeric()).count(); + let table = lua.create_table_with_capacity(seq_len, t.len() - seq_len)?; for (k, v) in t { - table.raw_set(k.into_lua(lua)?, v.into_lua(lua)?)?; + table.raw_set(k, v)?; } Ok(Value::Table(table)) } @@ -113,6 +116,11 @@ pub enum ValueSendableKey { String(Vec), } +impl ValueSendableKey { + #[inline] + fn is_numeric(&self) -> bool { matches!(self, Self::Integer(_) | Self::Number(_)) } +} + impl TryInto for ValueSendable { type Error = mlua::Error; diff --git a/yazi-plugin/src/elements/bar.rs b/yazi-plugin/src/elements/bar.rs index 8428b5a8..c7562753 100644 --- a/yazi-plugin/src/elements/bar.rs +++ b/yazi-plugin/src/elements/bar.rs @@ -1,4 +1,4 @@ -use mlua::{AnyUserData, ExternalError, IntoLua, Lua, Table, UserData, Value}; +use mlua::{AnyUserData, ExternalError, Lua, Table, UserData, Value}; use ratatui::widgets::Borders; use super::{RectRef, Renderable, Style}; @@ -26,12 +26,12 @@ impl Bar { let bar = lua.create_table_from([ // Direction - ("NONE", Borders::NONE.bits().into_lua(lua)?), - ("TOP", Borders::TOP.bits().into_lua(lua)?), - ("RIGHT", Borders::RIGHT.bits().into_lua(lua)?), - ("BOTTOM", Borders::BOTTOM.bits().into_lua(lua)?), - ("LEFT", Borders::LEFT.bits().into_lua(lua)?), - ("ALL", Borders::ALL.bits().into_lua(lua)?), + ("NONE", Borders::NONE.bits()), + ("TOP", Borders::TOP.bits()), + ("RIGHT", Borders::RIGHT.bits()), + ("BOTTOM", Borders::BOTTOM.bits()), + ("LEFT", Borders::LEFT.bits()), + ("ALL", Borders::ALL.bits()), ])?; bar.set_metatable(Some(lua.create_table_from([("__call", new)])?)); diff --git a/yazi-plugin/src/elements/border.rs b/yazi-plugin/src/elements/border.rs index ec815402..973bdb7f 100644 --- a/yazi-plugin/src/elements/border.rs +++ b/yazi-plugin/src/elements/border.rs @@ -1,4 +1,4 @@ -use mlua::{AnyUserData, ExternalError, IntoLua, Lua, Table, UserData, Value}; +use mlua::{AnyUserData, ExternalError, Lua, Table, UserData, Value}; use ratatui::widgets::{Borders, Widget}; use super::{RectRef, Renderable, Style}; @@ -32,19 +32,19 @@ impl Border { let border = lua.create_table_from([ // Position - ("NONE", Borders::NONE.bits().into_lua(lua)?), - ("TOP", Borders::TOP.bits().into_lua(lua)?), - ("RIGHT", Borders::RIGHT.bits().into_lua(lua)?), - ("BOTTOM", Borders::BOTTOM.bits().into_lua(lua)?), - ("LEFT", Borders::LEFT.bits().into_lua(lua)?), - ("ALL", Borders::ALL.bits().into_lua(lua)?), + ("NONE", Borders::NONE.bits()), + ("TOP", Borders::TOP.bits()), + ("RIGHT", Borders::RIGHT.bits()), + ("BOTTOM", Borders::BOTTOM.bits()), + ("LEFT", Borders::LEFT.bits()), + ("ALL", Borders::ALL.bits()), // Type - ("PLAIN", PLAIN.into_lua(lua)?), - ("ROUNDED", ROUNDED.into_lua(lua)?), - ("DOUBLE", DOUBLE.into_lua(lua)?), - ("THICK", THICK.into_lua(lua)?), - ("QUADRANT_INSIDE", QUADRANT_INSIDE.into_lua(lua)?), - ("QUADRANT_OUTSIDE", QUADRANT_OUTSIDE.into_lua(lua)?), + ("PLAIN", PLAIN), + ("ROUNDED", ROUNDED), + ("DOUBLE", DOUBLE), + ("THICK", THICK), + ("QUADRANT_INSIDE", QUADRANT_INSIDE), + ("QUADRANT_OUTSIDE", QUADRANT_OUTSIDE), ])?; border.set_metatable(Some(lua.create_table_from([("__call", new)])?)); diff --git a/yazi-plugin/src/elements/clear.rs b/yazi-plugin/src/elements/clear.rs new file mode 100644 index 00000000..dfd0e2f4 --- /dev/null +++ b/yazi-plugin/src/elements/clear.rs @@ -0,0 +1,75 @@ +use std::sync::atomic::{AtomicBool, Ordering}; + +use mlua::{Lua, Table, UserData}; +use ratatui::layout::Rect; +use yazi_adaptor::ADAPTOR; + +use super::{RectRef, Renderable}; + +pub static COLLISION: AtomicBool = AtomicBool::new(false); + +#[derive(Clone, Copy, Default)] +pub struct Clear { + pub area: ratatui::layout::Rect, +} + +impl Clear { + pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { + let new = lua.create_function(|_, (_, area): (Table, RectRef)| Ok(Clear { area: *area }))?; + + let clear = lua.create_table()?; + clear.set_metatable(Some(lua.create_table_from([("__call", new)])?)); + + ui.raw_set("Clear", clear) + } +} + +impl ratatui::widgets::Widget for Clear { + fn render(self, area: Rect, buf: &mut ratatui::prelude::Buffer) + where + Self: Sized, + { + ratatui::widgets::Clear.render(area, buf); + + let Some(r) = ADAPTOR.shown_load().and_then(|r| overlap(&area, &r)) else { + return; + }; + + ADAPTOR.image_erase(r).ok(); + COLLISION.store(true, Ordering::Relaxed); + for y in area.top()..area.bottom() { + for x in area.left()..area.right() { + buf.get_mut(x, y).set_skip(true); + } + } + } +} + +impl Renderable for Clear { + fn area(&self) -> ratatui::layout::Rect { self.area } + + fn render(self: Box, buf: &mut ratatui::buffer::Buffer) { + ::render(Default::default(), self.area, buf); + } + + fn clone_render(&self, buf: &mut ratatui::buffer::Buffer) { Box::new(*self).render(buf); } +} + +impl UserData for Clear {} + +#[inline] +const fn is_overlapping(a: &Rect, b: &Rect) -> bool { + a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y +} + +fn overlap(a: &Rect, b: &Rect) -> Option { + if !is_overlapping(a, b) { + return None; + } + + let x = a.x.max(b.x); + let y = a.y.max(b.y); + let width = (a.x + a.width).min(b.x + b.width) - x; + let height = (a.y + a.height).min(b.y + b.height) - y; + Some(Rect { x, y, width, height }) +} diff --git a/yazi-plugin/src/elements/elements.rs b/yazi-plugin/src/elements/elements.rs index caa96606..0fb8fc35 100644 --- a/yazi-plugin/src/elements/elements.rs +++ b/yazi-plugin/src/elements/elements.rs @@ -12,6 +12,7 @@ pub fn pour(lua: &Lua) -> mlua::Result<()> { // Install super::Bar::install(lua, &ui)?; super::Border::install(lua, &ui)?; + super::Clear::install(lua, &ui)?; super::Constraint::install(lua, &ui)?; super::Gauge::install(lua, &ui)?; super::Layout::install(lua, &ui)?; diff --git a/yazi-plugin/src/elements/layout.rs b/yazi-plugin/src/elements/layout.rs index 0d8ac883..8b3eaa46 100644 --- a/yazi-plugin/src/elements/layout.rs +++ b/yazi-plugin/src/elements/layout.rs @@ -1,4 +1,4 @@ -use mlua::{AnyUserData, IntoLua, Lua, Table, UserData, UserDataMethods}; +use mlua::{AnyUserData, Lua, Table, UserData, UserDataMethods}; use super::{Constraint, Rect, RectRef}; use crate::bindings::Cast; @@ -17,10 +17,7 @@ impl Layout { pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> { let new = lua.create_function(|_, _: Table| Ok(Self::default()))?; - let layout = lua.create_table_from([ - ("HORIZONTAL", HORIZONTAL.into_lua(lua)?), - ("VERTICAL", VERTICAL.into_lua(lua)?), - ])?; + let layout = lua.create_table_from([("HORIZONTAL", HORIZONTAL), ("VERTICAL", VERTICAL)])?; layout.set_metatable(Some(lua.create_table_from([("__call", new)])?)); diff --git a/yazi-plugin/src/elements/mod.rs b/yazi-plugin/src/elements/mod.rs index 0ac6f401..b15488b3 100644 --- a/yazi-plugin/src/elements/mod.rs +++ b/yazi-plugin/src/elements/mod.rs @@ -2,6 +2,7 @@ mod bar; mod border; +mod clear; mod constraint; mod elements; mod gauge; @@ -16,6 +17,7 @@ mod style; pub use bar::*; pub use border::*; +pub use clear::*; pub use constraint::*; pub use elements::*; pub use gauge::*; diff --git a/yazi-plugin/src/elements/rect.rs b/yazi-plugin/src/elements/rect.rs index 45d233cf..26bb5eab 100644 --- a/yazi-plugin/src/elements/rect.rs +++ b/yazi-plugin/src/elements/rect.rs @@ -1,4 +1,4 @@ -use mlua::{AnyUserData, IntoLua, Lua, Table, UserDataFields, UserDataMethods, UserDataRef}; +use mlua::{AnyUserData, Lua, Table, UserDataFields, UserDataMethods, UserDataRef}; use super::PaddingRef; use crate::bindings::Cast; @@ -18,10 +18,7 @@ impl Rect { }) })?; - let rect = lua.create_table_from([( - "default", - Rect::cast(lua, ratatui::layout::Rect::default())?.into_lua(lua)?, - )])?; + let rect = lua.create_table_from([("default", Rect::cast(lua, Default::default())?)])?; rect.set_metatable(Some(lua.create_table_from([("__call", new)])?)); diff --git a/yazi-plugin/src/fs/fs.rs b/yazi-plugin/src/fs/fs.rs index 9e920240..aa3ecf9e 100644 --- a/yazi-plugin/src/fs/fs.rs +++ b/yazi-plugin/src/fs/fs.rs @@ -1,4 +1,4 @@ -use mlua::{IntoLua, Lua, Value}; +use mlua::{IntoLuaMulti, Lua, Value}; use tokio::fs; use crate::{bindings::{Cast, Cha}, url::UrlRef}; @@ -10,28 +10,28 @@ pub fn install(lua: &Lua) -> mlua::Result<()> { ( "write", lua.create_async_function(|lua, (url, data): (UrlRef, mlua::String)| async move { - Ok(match fs::write(&*url, data).await { - Ok(_) => (Value::Boolean(true), Value::Nil), - Err(e) => (Value::Boolean(false), e.raw_os_error().into_lua(lua)?), - }) + match fs::write(&*url, data).await { + Ok(_) => (true, Value::Nil).into_lua_multi(lua), + Err(e) => (false, e.raw_os_error()).into_lua_multi(lua), + } })?, ), ( "cha", lua.create_async_function(|lua, url: UrlRef| async move { - Ok(match fs::symlink_metadata(&*url).await { - Ok(m) => (Cha::cast(lua, m)?.into_lua(lua)?, Value::Nil), - Err(e) => (Value::Nil, e.raw_os_error().into_lua(lua)?), - }) + match fs::symlink_metadata(&*url).await { + Ok(m) => (Cha::cast(lua, m)?, Value::Nil).into_lua_multi(lua), + Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(lua), + } })?, ), ( "cha_follow", lua.create_async_function(|lua, url: UrlRef| async move { - Ok(match fs::metadata(&*url).await { - Ok(m) => (Cha::cast(lua, m)?.into_lua(lua)?, Value::Nil), - Err(e) => (Value::Nil, e.raw_os_error().into_lua(lua)?), - }) + match fs::metadata(&*url).await { + Ok(m) => (Cha::cast(lua, m)?, Value::Nil).into_lua_multi(lua), + Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(lua), + } })?, ), ])?, diff --git a/yazi-plugin/src/process/child.rs b/yazi-plugin/src/process/child.rs index 18c9d0e7..76242ae0 100644 --- a/yazi-plugin/src/process/child.rs +++ b/yazi-plugin/src/process/child.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use mlua::{IntoLua, Table, UserData, Value}; +use mlua::{IntoLuaMulti, Table, UserData, Value}; use tokio::{io::{AsyncBufReadExt, AsyncReadExt, BufReader}, process::{ChildStderr, ChildStdin, ChildStdout}, select}; use super::Status; @@ -68,16 +68,14 @@ impl UserData for Child { } }); methods.add_async_method_mut("wait", |lua, me, ()| async move { - Ok(match me.inner.wait().await { - Ok(status) => (Status::new(status).into_lua(lua)?, Value::Nil), - Err(e) => (Value::Nil, e.raw_os_error().into_lua(lua)?), - }) + match me.inner.wait().await { + Ok(status) => (Status::new(status), Value::Nil).into_lua_multi(lua), + Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(lua), + } }); - methods.add_method_mut("start_kill", |lua, me, ()| { - Ok(match me.inner.start_kill() { - Ok(_) => (true, Value::Nil), - Err(e) => (false, e.raw_os_error().into_lua(lua)?), - }) + methods.add_method_mut("start_kill", |lua, me, ()| match me.inner.start_kill() { + Ok(_) => (true, Value::Nil).into_lua_multi(lua), + Err(e) => (false, e.raw_os_error()).into_lua_multi(lua), }); } } diff --git a/yazi-plugin/src/process/command.rs b/yazi-plugin/src/process/command.rs index 3b67fa5e..be57d68a 100644 --- a/yazi-plugin/src/process/command.rs +++ b/yazi-plugin/src/process/command.rs @@ -1,6 +1,6 @@ use std::process::Stdio; -use mlua::{AnyUserData, IntoLua, Lua, Table, UserData, Value}; +use mlua::{AnyUserData, IntoLuaMulti, Lua, Table, UserData, Value}; use super::{output::Output, Child}; @@ -23,9 +23,9 @@ impl Command { let command = lua.create_table_from([ // Stdio - ("NULL", NULL.into_lua(lua)?), - ("PIPED", PIPED.into_lua(lua)?), - ("INHERIT", INHERIT.into_lua(lua)?), + ("NULL", NULL), + ("PIPED", PIPED), + ("INHERIT", INHERIT), ])?; command.set_metatable(Some(lua.create_table_from([("__call", new)])?)); @@ -86,17 +86,15 @@ impl UserData for Command { }); Ok(ud) }); - methods.add_method_mut("spawn", |lua, me, ()| { - Ok(match me.inner.spawn() { - Ok(child) => (Child::new(child).into_lua(lua)?, Value::Nil), - Err(e) => (Value::Nil, e.raw_os_error().into_lua(lua)?), - }) + methods.add_method_mut("spawn", |lua, me, ()| match me.inner.spawn() { + Ok(child) => (Child::new(child), Value::Nil).into_lua_multi(lua), + Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(lua), }); methods.add_async_method_mut("output", |lua, me, ()| async move { - Ok(match me.inner.output().await { - Ok(output) => (Output::new(output).into_lua(lua)?, Value::Nil), - Err(e) => (Value::Nil, e.raw_os_error().into_lua(lua)?), - }) + match me.inner.output().await { + Ok(output) => (Output::new(output), Value::Nil).into_lua_multi(lua), + Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(lua), + } }); } }