From 4a4ce25768b5fae4935d430e09e5167a1b39a918 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Wed, 25 Mar 2026 19:21:04 +0800 Subject: [PATCH] feat: Vim-like `lua` action that runs an inline Lua snippet --- CHANGELOG.md | 1 + yazi-actor/src/app/lua.rs | 24 ++++++++++++++++++++++++ yazi-actor/src/app/mod.rs | 1 + yazi-dds/src/spark/spark.rs | 3 +++ yazi-fm/src/executor.rs | 15 +++++++++++++++ yazi-parser/src/app/lua.rs | 24 ++++++++++++++++++++++++ yazi-parser/src/app/mod.rs | 2 +- 7 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 yazi-actor/src/app/lua.rs create mode 100644 yazi-parser/src/app/lua.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c3ea546..735b52e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - Custom tab name ([#3666]) - New `--in` for `search` action to set search directory ([#3696]) - Multi-file spotter ([#3733]) +- Vim-like `lua` action that runs an inline Lua snippet ([#1234]) - Certificate authentication for SFTP VFS provider ([#3716]) - New `hovered` condition specifying different icons for hovered files ([#3728]) - Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638]) diff --git a/yazi-actor/src/app/lua.rs b/yazi-actor/src/app/lua.rs new file mode 100644 index 00000000..ed171e2a --- /dev/null +++ b/yazi-actor/src/app/lua.rs @@ -0,0 +1,24 @@ +use anyhow::Result; +use yazi_dds::Sendable; +use yazi_macro::succ; +use yazi_parser::app::LuaOpt; +use yazi_plugin::LUA; +use yazi_shared::data::Data; + +use crate::{Actor, Ctx, lives::Lives}; + +pub struct Lua; + +impl Actor for Lua { + type Options = LuaOpt; + + const NAME: &str = "lua"; + + fn act(cx: &mut Ctx, opt: Self::Options) -> Result { + let result = Lives::scope(cx.core, || { + let chunk = LUA.load(&*opt.code).set_name("anonymous"); + Sendable::value_to_data(&LUA, chunk.eval()?) + }); + succ!(result?); + } +} diff --git a/yazi-actor/src/app/mod.rs b/yazi-actor/src/app/mod.rs index 36cab3fb..931cacbf 100644 --- a/yazi-actor/src/app/mod.rs +++ b/yazi-actor/src/app/mod.rs @@ -3,6 +3,7 @@ yazi_macro::mod_flat!( bootstrap deprecate focus + lua mouse plugin plugin_do diff --git a/yazi-dds/src/spark/spark.rs b/yazi-dds/src/spark/spark.rs index a7a1ba9e..9fddb178 100644 --- a/yazi-dds/src/spark/spark.rs +++ b/yazi-dds/src/spark/spark.rs @@ -12,6 +12,7 @@ pub enum Spark<'a> { AppBootstrap(yazi_parser::VoidOpt), AppDeprecate(yazi_parser::app::DeprecateOpt), AppFocus(yazi_parser::VoidOpt), + AppLua(yazi_parser::app::LuaOpt), AppMouse(yazi_parser::app::MouseOpt), AppPlugin(yazi_parser::app::PluginOpt), AppPluginDo(yazi_parser::app::PluginOpt), @@ -194,6 +195,7 @@ impl<'a> IntoLua for Spark<'a> { Self::AppBootstrap(b) => b.into_lua(lua), Self::AppDeprecate(b) => b.into_lua(lua), Self::AppFocus(b) => b.into_lua(lua), + Self::AppLua(b) => b.into_lua(lua), Self::AppMouse(b) => b.into_lua(lua), Self::AppPlugin(b) => b.into_lua(lua), Self::AppPluginDo(b) => b.into_lua(lua), @@ -364,6 +366,7 @@ try_from_spark!( // App try_from_spark!(yazi_parser::ArrowOpt, mgr:arrow, mgr:tab_swap); try_from_spark!(yazi_parser::app::DeprecateOpt, app:deprecate); +try_from_spark!(yazi_parser::app::LuaOpt, app:lua); try_from_spark!(yazi_parser::app::MouseOpt, app:mouse); try_from_spark!(yazi_parser::app::PluginOpt, app:plugin, app:plugin_do); try_from_spark!(yazi_parser::app::QuitOpt, app:quit, mgr:quit); diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index 05205532..d9a0460b 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -45,6 +45,7 @@ impl<'a> Executor<'a> { on!(plugin); on!(plugin_do); on!(update_progress); + on!(lua); on!(deprecate); on!(quit); @@ -156,6 +157,8 @@ impl<'a> Executor<'a> { "help" => act!(help:toggle, cx, Layer::Mgr), // Plugin "plugin" => act!(app:plugin, cx, action), + // Lua + "lua" => act!(app:lua, cx, action), _ => succ!(), } } @@ -186,6 +189,8 @@ impl<'a> Executor<'a> { "help" => act!(help:toggle, cx, Layer::Tasks), // Plugin "plugin" => act!(app:plugin, cx, action), + // Lua + "lua" => act!(app:lua, cx, action), _ => succ!(), } } @@ -211,6 +216,8 @@ impl<'a> Executor<'a> { "help" => act!(help:toggle, cx, Layer::Spot), // Plugin "plugin" => act!(app:plugin, cx, action), + // Lua + "lua" => act!(app:lua, cx, action), _ => succ!(), } } @@ -235,6 +242,8 @@ impl<'a> Executor<'a> { "help" => act!(help:toggle, cx, Layer::Pick), // Plugin "plugin" => act!(app:plugin, cx, action), + // Lua + "lua" => act!(app:lua, cx, action), _ => succ!(), } } @@ -262,6 +271,8 @@ impl<'a> Executor<'a> { "help" => return act!(help:toggle, cx, Layer::Input), // Plugin "plugin" => return act!(app:plugin, cx, action), + // Lua + "lua" => return act!(app:lua, cx, action), _ => {} } } @@ -312,6 +323,8 @@ impl<'a> Executor<'a> { "close" => act!(help:toggle, cx, Layer::Help), // Plugin "plugin" => act!(app:plugin, cx, action), + // Lua + "lua" => act!(app:lua, cx, action), _ => succ!(), } } @@ -337,6 +350,8 @@ impl<'a> Executor<'a> { "help" => act!(help:toggle, cx, Layer::Cmp), // Plugin "plugin" => act!(app:plugin, cx, action), + // Lua + "lua" => act!(app:lua, cx, action), _ => succ!(), } } diff --git a/yazi-parser/src/app/lua.rs b/yazi-parser/src/app/lua.rs new file mode 100644 index 00000000..b6ece619 --- /dev/null +++ b/yazi-parser/src/app/lua.rs @@ -0,0 +1,24 @@ +use std::fmt::Debug; + +use anyhow::Result; +use mlua::{ExternalError, FromLua, IntoLua, Lua, Value}; +use yazi_shared::{SStr, event::ActionCow}; + +#[derive(Clone, Debug, Default)] +pub struct LuaOpt { + pub code: SStr, +} + +impl TryFrom for LuaOpt { + type Error = anyhow::Error; + + fn try_from(mut a: ActionCow) -> Result { Ok(Self { code: a.take_first()? }) } +} + +impl FromLua for LuaOpt { + fn from_lua(_: Value, _: &Lua) -> mlua::Result { Err("unsupported".into_lua_err()) } +} + +impl IntoLua for LuaOpt { + fn into_lua(self, _: &Lua) -> mlua::Result { Err("unsupported".into_lua_err()) } +} diff --git a/yazi-parser/src/app/mod.rs b/yazi-parser/src/app/mod.rs index 8f7ac2c4..ce380fb9 100644 --- a/yazi-parser/src/app/mod.rs +++ b/yazi-parser/src/app/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(deprecate mouse plugin quit reflow resume stop title update_progress); +yazi_macro::mod_flat!(deprecate lua mouse plugin quit reflow resume stop title update_progress);