mirror of
https://github.com/sxyazi/yazi.git
synced 2024-11-27 14:03:29 +03:00
perf: lazy load ui
, ya
, fs
, and ps
(#1903)
This commit is contained in:
parent
4ff4038b41
commit
00486521b8
10
.github/workflows/check.yml
vendored
10
.github/workflows/check.yml
vendored
@ -6,6 +6,10 @@ on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: true
|
||||
RUSTC_WRAPPER: sccache
|
||||
|
||||
jobs:
|
||||
clippy:
|
||||
runs-on: ubuntu-latest
|
||||
@ -23,6 +27,9 @@ jobs:
|
||||
prefix-key: rust
|
||||
shared-key: ubuntu-latest@debug
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.6
|
||||
|
||||
- name: Clippy
|
||||
run: cargo clippy --all
|
||||
|
||||
@ -43,6 +50,9 @@ jobs:
|
||||
prefix-key: rust
|
||||
shared-key: ubuntu-latest@debug
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.6
|
||||
|
||||
- name: Rustfmt
|
||||
run: cargo +nightly fmt --all -- --check
|
||||
|
||||
|
16
.github/workflows/draft.yml
vendored
16
.github/workflows/draft.yml
vendored
@ -8,6 +8,10 @@ on:
|
||||
- cron: "0 */6 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: true
|
||||
RUSTC_WRAPPER: sccache
|
||||
|
||||
jobs:
|
||||
build-unix:
|
||||
strategy:
|
||||
@ -41,6 +45,9 @@ jobs:
|
||||
prefix-key: rust
|
||||
shared-key: ${{ matrix.target }}@release
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.6
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
@ -71,6 +78,9 @@ jobs:
|
||||
prefix-key: rust
|
||||
shared-key: ${{ matrix.target }}@release
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.6
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
YAZI_GEN_COMPLETIONS: true
|
||||
@ -119,6 +129,9 @@ jobs:
|
||||
prefix-key: rust
|
||||
shared-key: ${{ matrix.target }}@release
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.6
|
||||
|
||||
- name: Build
|
||||
run: ./scripts/build.sh ${{ matrix.target }}
|
||||
|
||||
@ -144,6 +157,9 @@ jobs:
|
||||
prefix-key: rust
|
||||
shared-key: ${{ matrix.target }}@release
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.6
|
||||
|
||||
- name: Build
|
||||
uses: snapcore/action-build@v1
|
||||
|
||||
|
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@ -7,6 +7,8 @@ on:
|
||||
branches: [main]
|
||||
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: true
|
||||
RUSTC_WRAPPER: sccache
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
@ -27,6 +29,9 @@ jobs:
|
||||
prefix-key: rust
|
||||
shared-key: ${{ matrix.os }}@debug
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.6
|
||||
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
|
||||
|
54
Cargo.lock
generated
54
Cargo.lock
generated
@ -34,9 +34,9 @@ checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.19"
|
||||
version = "0.2.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "611cc2ae7d2e242c457e4be7f97036b8ad9ca152b499f53faf99b1ed8fc2553f"
|
||||
checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
@ -327,9 +327,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.37"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf"
|
||||
checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@ -657,6 +657,12 @@ dependencies = [
|
||||
"syn 2.0.87",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@ -1282,10 +1288,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "instability"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c"
|
||||
checksum = "b829f37dead9dc39df40c2d3376c179fdfd2ac771f53f55d3c30dc096a3c0c6e"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"indoc",
|
||||
"pretty_assertions",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.87",
|
||||
]
|
||||
@ -1901,6 +1911,16 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
@ -2152,9 +2172,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.8"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@ -2196,9 +2216,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.39"
|
||||
version = "0.38.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee"
|
||||
checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"errno",
|
||||
@ -2242,9 +2262,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.214"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
|
||||
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
@ -2261,9 +2281,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.214"
|
||||
version = "1.0.215"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
|
||||
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -3326,6 +3346,12 @@ version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yazi-adapter"
|
||||
version = "0.3.3"
|
||||
|
@ -11,7 +11,7 @@ impl BodyBye {
|
||||
pub fn owned() -> Body<'static> { Self.into() }
|
||||
}
|
||||
|
||||
impl<'a> From<BodyBye> for Body<'a> {
|
||||
impl From<BodyBye> for Body<'_> {
|
||||
fn from(value: BodyBye) -> Self { Self::Bye(value) }
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ impl BodyTab {
|
||||
pub fn owned(idx: usize) -> Body<'static> { Self { idx }.into() }
|
||||
}
|
||||
|
||||
impl<'a> From<BodyTab> for Body<'a> {
|
||||
impl From<BodyTab> for Body<'_> {
|
||||
fn from(value: BodyTab) -> Self { Self::Tab(value) }
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ use crossterm::event::{MouseEvent, MouseEventKind};
|
||||
use mlua::{ObjectLike, Table};
|
||||
use tracing::error;
|
||||
use yazi_config::MANAGER;
|
||||
use yazi_plugin::{LUA, bindings::Cast};
|
||||
use yazi_plugin::LUA;
|
||||
|
||||
use crate::{app::App, lives::Lives};
|
||||
|
||||
@ -17,30 +17,29 @@ impl From<MouseEvent> for Opt {
|
||||
impl App {
|
||||
#[yazi_codegen::command]
|
||||
pub fn mouse(&mut self, opt: Opt) {
|
||||
let event = opt.event;
|
||||
let event = yazi_plugin::bindings::MouseEvent::from(opt.event);
|
||||
let Some(size) = self.term.as_ref().and_then(|t| t.size().ok()) else { return };
|
||||
let Ok(evt) = yazi_plugin::bindings::MouseEvent::cast(&LUA, event) else { return };
|
||||
|
||||
let res = Lives::scope(&self.cx, move || {
|
||||
let area = yazi_plugin::elements::Rect::from(size);
|
||||
let root = LUA.globals().raw_get::<Table>("Root")?.call_method::<Table>("new", area)?;
|
||||
|
||||
if matches!(event.kind, MouseEventKind::Down(_) if MANAGER.mouse_events.draggable()) {
|
||||
root.raw_set("_drag_start", evt.clone())?;
|
||||
root.raw_set("_drag_start", event)?;
|
||||
}
|
||||
|
||||
match event.kind {
|
||||
MouseEventKind::Down(_) => root.call_method("click", (evt, false))?,
|
||||
MouseEventKind::Up(_) => root.call_method("click", (evt, true))?,
|
||||
MouseEventKind::Down(_) => root.call_method("click", (event, false))?,
|
||||
MouseEventKind::Up(_) => root.call_method("click", (event, true))?,
|
||||
|
||||
MouseEventKind::ScrollDown => root.call_method("scroll", (evt, 1))?,
|
||||
MouseEventKind::ScrollUp => root.call_method("scroll", (evt, -1))?,
|
||||
MouseEventKind::ScrollDown => root.call_method("scroll", (event, 1))?,
|
||||
MouseEventKind::ScrollUp => root.call_method("scroll", (event, -1))?,
|
||||
|
||||
MouseEventKind::ScrollRight => root.call_method("touch", (evt, 1))?,
|
||||
MouseEventKind::ScrollLeft => root.call_method("touch", (evt, -1))?,
|
||||
MouseEventKind::ScrollRight => root.call_method("touch", (event, 1))?,
|
||||
MouseEventKind::ScrollLeft => root.call_method("touch", (event, -1))?,
|
||||
|
||||
MouseEventKind::Moved => root.call_method("move", evt)?,
|
||||
MouseEventKind::Drag(_) => root.call_method("drag", evt)?,
|
||||
MouseEventKind::Moved => root.call_method("move", event)?,
|
||||
MouseEventKind::Drag(_) => root.call_method("drag", event)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -33,10 +33,10 @@ impl App {
|
||||
};
|
||||
|
||||
let id: mlua::String = t.get("_id")?;
|
||||
match id.to_str()?.as_ref() {
|
||||
"current" => layout.current = *t.raw_get::<yazi_plugin::elements::Rect>("_area")?,
|
||||
"preview" => layout.preview = *t.raw_get::<yazi_plugin::elements::Rect>("_area")?,
|
||||
"progress" => layout.progress = *t.raw_get::<yazi_plugin::elements::Rect>("_area")?,
|
||||
match id.as_bytes().as_ref() {
|
||||
b"current" => layout.current = *t.raw_get::<yazi_plugin::elements::Rect>("_area")?,
|
||||
b"preview" => layout.preview = *t.raw_get::<yazi_plugin::elements::Rect>("_area")?,
|
||||
b"progress" => layout.progress = *t.raw_get::<yazi_plugin::elements::Rect>("_area")?,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ impl<'a> Completion<'a> {
|
||||
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
|
||||
}
|
||||
|
||||
impl<'a> Widget for Completion<'a> {
|
||||
impl Widget for Completion<'_> {
|
||||
fn render(self, rect: Rect, buf: &mut Buffer) {
|
||||
let items: Vec<_> = self
|
||||
.cx
|
||||
|
@ -11,7 +11,7 @@ impl<'a> Confirm<'a> {
|
||||
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
|
||||
}
|
||||
|
||||
impl<'a> Widget for Confirm<'a> {
|
||||
impl Widget for Confirm<'_> {
|
||||
fn render(self, _win: Rect, buf: &mut Buffer) {
|
||||
let confirm = &self.cx.confirm;
|
||||
let area = self.cx.manager.area(confirm.position);
|
||||
|
@ -9,7 +9,7 @@ impl<'a> Content<'a> {
|
||||
pub(crate) fn new(p: Paragraph<'a>) -> Self { Self { p } }
|
||||
}
|
||||
|
||||
impl<'a> Widget for Content<'a> {
|
||||
impl Widget for Content<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
// Content area
|
||||
let inner = area.inner(Margin::new(1, 0));
|
||||
|
@ -11,7 +11,7 @@ impl<'a> List<'a> {
|
||||
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
|
||||
}
|
||||
|
||||
impl<'a> Widget for List<'a> {
|
||||
impl Widget for List<'_> {
|
||||
fn render(self, mut area: Rect, buf: &mut Buffer) {
|
||||
// List content area
|
||||
let inner = area.inner(Margin::new(2, 0));
|
||||
|
@ -19,7 +19,7 @@ impl<'a> Help<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for Help<'a> {
|
||||
impl Widget for Help<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let help = &self.cx.help;
|
||||
yazi_plugin::elements::Clear::default().render(area, buf);
|
||||
|
@ -21,7 +21,7 @@ impl<'a> Input<'a> {
|
||||
bail!("Highlighting is disabled");
|
||||
}
|
||||
|
||||
let (theme, syntaxes) = futures::executor::block_on(Highlighter::init());
|
||||
let (theme, syntaxes) = Highlighter::init();
|
||||
if let Some(syntax) = syntaxes.find_syntax_by_name("Bourne Again Shell (bash)") {
|
||||
let mut h = HighlightLines::new(syntax, theme);
|
||||
let regions = h.highlight_line(self.cx.input.value(), syntaxes)?;
|
||||
@ -31,7 +31,7 @@ impl<'a> Input<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for Input<'a> {
|
||||
impl Widget for Input<'_> {
|
||||
fn render(self, win: Rect, buf: &mut Buffer) {
|
||||
let input = &self.cx.input;
|
||||
let area = self.cx.manager.area(input.position);
|
||||
|
@ -38,7 +38,7 @@ impl<'a> Notify<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for Notify<'a> {
|
||||
impl Widget for Notify<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let notify = &self.cx.notify;
|
||||
|
||||
|
@ -11,7 +11,7 @@ impl<'a> Pick<'a> {
|
||||
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
|
||||
}
|
||||
|
||||
impl<'a> Widget for Pick<'a> {
|
||||
impl Widget for Pick<'_> {
|
||||
fn render(self, _: Rect, buf: &mut Buffer) {
|
||||
let pick = &self.cx.pick;
|
||||
let area = self.cx.manager.area(pick.position);
|
||||
|
@ -20,7 +20,7 @@ impl<'a> Root<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for Root<'a> {
|
||||
impl Widget for Root<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let mut f = || {
|
||||
let area = yazi_plugin::elements::Rect::from(area);
|
||||
|
@ -28,7 +28,7 @@ impl<'a> Tasks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for Tasks<'a> {
|
||||
impl Widget for Tasks<'_> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
let area = Self::area(area);
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
table.unpack = table.unpack or unpack
|
||||
|
||||
ya = ya or {}
|
||||
|
||||
function ya.clamp(min, x, max)
|
||||
if x < min then
|
||||
return min
|
||||
|
159
yazi-plugin/src/bindings/cha.rs
Normal file
159
yazi-plugin/src/bindings/cha.rs
Normal file
@ -0,0 +1,159 @@
|
||||
use std::{ops::Deref, time::{Duration, SystemTime, UNIX_EPOCH}};
|
||||
|
||||
use mlua::{ExternalError, IntoLua, Lua, Table, UserData, UserDataFields, UserDataMethods};
|
||||
use yazi_shared::fs::ChaKind;
|
||||
|
||||
use crate::RtRef;
|
||||
|
||||
pub struct Cha(yazi_shared::fs::Cha);
|
||||
|
||||
impl Deref for Cha {
|
||||
type Target = yazi_shared::fs::Cha;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl<T: Into<yazi_shared::fs::Cha>> From<T> for Cha {
|
||||
fn from(cha: T) -> Self { Self(cha.into()) }
|
||||
}
|
||||
|
||||
static WARNED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||
|
||||
#[inline]
|
||||
fn warn_deprecated(id: Option<&str>) {
|
||||
if !WARNED.swap(true, std::sync::atomic::Ordering::Relaxed) {
|
||||
let id = match id {
|
||||
Some(id) => format!("`{id}.yazi` plugin"),
|
||||
None => "`init.lua` config".to_owned(),
|
||||
};
|
||||
let s = "The `created`, `modified`, `accessed`, `length`, and `permissions` properties of `Cha` have been renamed in Yazi v0.4.
|
||||
|
||||
Please use the new `btime`, `mtime`, `atime`, `len`, and `perm` instead, in your {id}. See #1772 for details: https://github.com/sxyazi/yazi/issues/1772";
|
||||
yazi_proxy::AppProxy::notify(yazi_proxy::options::NotifyOpt {
|
||||
title: "Deprecated API".to_owned(),
|
||||
content: s.replace("{id}", &id),
|
||||
level: yazi_proxy::options::NotifyLevel::Warn,
|
||||
timeout: Duration::from_secs(20),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Cha {
|
||||
pub fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
#[inline]
|
||||
fn parse_time(f: Option<f64>) -> mlua::Result<Option<SystemTime>> {
|
||||
Ok(match f {
|
||||
Some(n) if n >= 0.0 => Some(SystemTime::UNIX_EPOCH + Duration::from_secs_f64(n)),
|
||||
Some(n) => Err(format!("Invalid timestamp: {n}").into_lua_err())?,
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
||||
lua.globals().raw_set(
|
||||
"Cha",
|
||||
lua.create_function(|lua, t: Table| {
|
||||
let kind =
|
||||
ChaKind::from_bits(t.raw_get("kind")?).ok_or_else(|| "Invalid kind".into_lua_err())?;
|
||||
|
||||
Self::from(yazi_shared::fs::Cha {
|
||||
kind,
|
||||
len: t.raw_get("len").unwrap_or_default(),
|
||||
atime: parse_time(t.raw_get("atime").ok())?,
|
||||
btime: parse_time(t.raw_get("btime").ok())?,
|
||||
#[cfg(unix)]
|
||||
ctime: parse_time(t.raw_get("ctime").ok())?,
|
||||
mtime: parse_time(t.raw_get("mtime").ok())?,
|
||||
#[cfg(unix)]
|
||||
mode: t.raw_get("mode").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
uid: t.raw_get("uid").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
gid: t.raw_get("gid").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
nlink: t.raw_get("nlink").unwrap_or_default(),
|
||||
})
|
||||
.into_lua(lua)
|
||||
})?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Cha {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("is_dir", |_, me| Ok(me.is_dir()));
|
||||
fields.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
||||
fields.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
||||
fields.add_field_method_get("is_orphan", |_, me| Ok(me.is_orphan()));
|
||||
fields.add_field_method_get("is_dummy", |_, me| Ok(me.is_dummy()));
|
||||
fields.add_field_method_get("is_block", |_, me| Ok(me.is_block()));
|
||||
fields.add_field_method_get("is_char", |_, me| Ok(me.is_char()));
|
||||
fields.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo()));
|
||||
fields.add_field_method_get("is_sock", |_, me| Ok(me.is_sock()));
|
||||
fields.add_field_method_get("is_exec", |_, me| Ok(me.is_exec()));
|
||||
fields.add_field_method_get("is_sticky", |_, me| Ok(me.is_sticky()));
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
fields.add_field_method_get("uid", |_, me| Ok((!me.is_dummy()).then_some(me.uid)));
|
||||
fields.add_field_method_get("gid", |_, me| Ok((!me.is_dummy()).then_some(me.gid)));
|
||||
fields.add_field_method_get("nlink", |_, me| Ok((!me.is_dummy()).then_some(me.nlink)));
|
||||
}
|
||||
|
||||
fields.add_field_method_get("len", |_, me| Ok(me.len));
|
||||
fields.add_field_method_get("atime", |_, me| {
|
||||
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
fields.add_field_method_get("btime", |_, me| {
|
||||
Ok(me.btime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
#[cfg(unix)]
|
||||
fields.add_field_method_get("ctime", |_, me| {
|
||||
Ok(me.ctime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
fields.add_field_method_get("mtime", |_, me| {
|
||||
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
|
||||
// TODO: remove these deprecated properties in the future
|
||||
{
|
||||
fields.add_field_method_get("length", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.len)
|
||||
});
|
||||
fields.add_field_method_get("created", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.btime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
fields.add_field_method_get("modified", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
fields.add_field_method_get("accessed", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_method("perm", |_, _me, ()| {
|
||||
Ok(
|
||||
#[cfg(unix)]
|
||||
Some(yazi_shared::fs::permissions(_me.mode, _me.is_dummy())),
|
||||
#[cfg(windows)]
|
||||
None::<String>,
|
||||
)
|
||||
});
|
||||
|
||||
// TODO: remove these deprecated properties in the future
|
||||
methods.add_method("permissions", |lua, _me, ()| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(
|
||||
#[cfg(unix)]
|
||||
Some(yazi_shared::fs::permissions(_me.mode, _me.is_dummy())),
|
||||
#[cfg(windows)]
|
||||
None::<String>,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
@ -1,23 +1,24 @@
|
||||
use mlua::{AnyUserData, Lua, UserDataFields};
|
||||
use std::ops::Deref;
|
||||
|
||||
use mlua::{UserData, UserDataFields};
|
||||
|
||||
use super::Cast;
|
||||
use crate::elements::Style;
|
||||
|
||||
pub struct Icon;
|
||||
pub struct Icon(&'static yazi_shared::theme::Icon);
|
||||
|
||||
impl Icon {
|
||||
pub fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<&yazi_shared::theme::Icon>(|reg| {
|
||||
reg.add_field_method_get("text", |lua, me| lua.create_string(&me.text));
|
||||
reg.add_field_method_get("style", |_, me| Ok(Style::from(me.style)));
|
||||
})?;
|
||||
impl Deref for Icon {
|
||||
type Target = yazi_shared::theme::Icon;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn deref(&self) -> &Self::Target { self.0 }
|
||||
}
|
||||
|
||||
impl Cast<&'static yazi_shared::theme::Icon> for Icon {
|
||||
fn cast(lua: &Lua, data: &'static yazi_shared::theme::Icon) -> mlua::Result<AnyUserData> {
|
||||
lua.create_any_userdata(data)
|
||||
impl From<&'static yazi_shared::theme::Icon> for Icon {
|
||||
fn from(icon: &'static yazi_shared::theme::Icon) -> Self { Self(icon) }
|
||||
}
|
||||
|
||||
impl UserData for Icon {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("text", |lua, me| lua.create_string(&me.text));
|
||||
fields.add_field_method_get("style", |_, me| Ok(Style::from(me.style)));
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
yazi_macro::mod_flat!(bindings icon input mouse permit position range window);
|
||||
yazi_macro::mod_flat!(bindings cha icon input mouse permit position range window);
|
||||
|
@ -1,35 +1,36 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use crossterm::event::MouseButton;
|
||||
use mlua::{AnyUserData, Lua, UserDataFields};
|
||||
use mlua::{UserData, UserDataFields};
|
||||
|
||||
use super::Cast;
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MouseEvent(crossterm::event::MouseEvent);
|
||||
|
||||
pub struct MouseEvent;
|
||||
impl Deref for MouseEvent {
|
||||
type Target = crossterm::event::MouseEvent;
|
||||
|
||||
impl MouseEvent {
|
||||
pub fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<crossterm::event::MouseEvent>(|reg| {
|
||||
reg.add_field_method_get("x", |_, me| Ok(me.column));
|
||||
reg.add_field_method_get("y", |_, me| Ok(me.row));
|
||||
reg.add_field_method_get("is_left", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Left))
|
||||
});
|
||||
reg.add_field_method_get("is_right", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Right))
|
||||
});
|
||||
reg.add_field_method_get("is_middle", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Middle))
|
||||
});
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl Cast<crossterm::event::MouseEvent> for MouseEvent {
|
||||
fn cast(lua: &Lua, data: crossterm::event::MouseEvent) -> mlua::Result<AnyUserData> {
|
||||
lua.create_any_userdata(data)
|
||||
impl From<crossterm::event::MouseEvent> for MouseEvent {
|
||||
fn from(event: crossterm::event::MouseEvent) -> Self { Self(event) }
|
||||
}
|
||||
|
||||
impl UserData for MouseEvent {
|
||||
fn add_fields<F: UserDataFields<Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("x", |_, me| Ok(me.column));
|
||||
fields.add_field_method_get("y", |_, me| Ok(me.row));
|
||||
fields.add_field_method_get("is_left", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Left))
|
||||
});
|
||||
fields.add_field_method_get("is_right", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Right))
|
||||
});
|
||||
fields.add_field_method_get("is_middle", |_, me| {
|
||||
use crossterm::event::MouseEventKind as K;
|
||||
Ok(matches!(me.kind, K::Down(b) | K::Up(b) | K::Drag(b) if b == MouseButton::Middle))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,149 +0,0 @@
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use mlua::{AnyUserData, ExternalError, Lua, Table, UserDataFields, UserDataMethods};
|
||||
use yazi_shared::fs::ChaKind;
|
||||
|
||||
use crate::{RtRef, bindings::Cast};
|
||||
|
||||
pub struct Cha;
|
||||
|
||||
static WARNED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
|
||||
|
||||
#[inline]
|
||||
fn warn_deprecated(id: Option<&str>) {
|
||||
if !WARNED.swap(true, std::sync::atomic::Ordering::Relaxed) {
|
||||
let id = match id {
|
||||
Some(id) => format!("`{id}.yazi` plugin"),
|
||||
None => "`init.lua` config".to_owned(),
|
||||
};
|
||||
let s = "The `created`, `modified`, `accessed`, `length`, and `permissions` properties of `Cha` have been renamed in Yazi v0.4.
|
||||
|
||||
Please use the new `btime`, `mtime`, `atime`, `len`, and `perm` instead, in your {id}. See #1772 for details: https://github.com/sxyazi/yazi/issues/1772";
|
||||
yazi_proxy::AppProxy::notify(yazi_proxy::options::NotifyOpt {
|
||||
title: "Deprecated API".to_owned(),
|
||||
content: s.replace("{id}", &id),
|
||||
level: yazi_proxy::options::NotifyLevel::Warn,
|
||||
timeout: Duration::from_secs(20),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Cha {
|
||||
pub fn register(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.register_userdata_type::<yazi_shared::fs::Cha>(|reg| {
|
||||
reg.add_field_method_get("is_dir", |_, me| Ok(me.is_dir()));
|
||||
reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
|
||||
reg.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
||||
reg.add_field_method_get("is_orphan", |_, me| Ok(me.is_orphan()));
|
||||
reg.add_field_method_get("is_dummy", |_, me| Ok(me.is_dummy()));
|
||||
reg.add_field_method_get("is_block", |_, me| Ok(me.is_block()));
|
||||
reg.add_field_method_get("is_char", |_, me| Ok(me.is_char()));
|
||||
reg.add_field_method_get("is_fifo", |_, me| Ok(me.is_fifo()));
|
||||
reg.add_field_method_get("is_sock", |_, me| Ok(me.is_sock()));
|
||||
reg.add_field_method_get("is_exec", |_, me| Ok(me.is_exec()));
|
||||
reg.add_field_method_get("is_sticky", |_, me| Ok(me.is_sticky()));
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
reg.add_field_method_get("uid", |_, me| Ok((!me.is_dummy()).then_some(me.uid)));
|
||||
reg.add_field_method_get("gid", |_, me| Ok((!me.is_dummy()).then_some(me.gid)));
|
||||
reg.add_field_method_get("nlink", |_, me| Ok((!me.is_dummy()).then_some(me.nlink)));
|
||||
}
|
||||
|
||||
reg.add_field_method_get("len", |_, me| Ok(me.len));
|
||||
reg.add_field_method_get("atime", |_, me| {
|
||||
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
reg.add_field_method_get("btime", |_, me| {
|
||||
Ok(me.btime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
#[cfg(unix)]
|
||||
reg.add_field_method_get("ctime", |_, me| {
|
||||
Ok(me.ctime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
reg.add_field_method_get("mtime", |_, me| {
|
||||
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
reg.add_method("perm", |_, _me, ()| {
|
||||
Ok(
|
||||
#[cfg(unix)]
|
||||
Some(yazi_shared::fs::permissions(_me.mode, _me.is_dummy())),
|
||||
#[cfg(windows)]
|
||||
None::<String>,
|
||||
)
|
||||
});
|
||||
|
||||
// TODO: remove these deprecated properties in the future
|
||||
{
|
||||
reg.add_field_method_get("length", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.len)
|
||||
});
|
||||
reg.add_field_method_get("created", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.btime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
reg.add_field_method_get("modified", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.mtime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
reg.add_field_method_get("accessed", |lua, me| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(me.atime.and_then(|t| t.duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok()))
|
||||
});
|
||||
reg.add_method("permissions", |lua, _me, ()| {
|
||||
warn_deprecated(lua.named_registry_value::<RtRef>("rt")?.current());
|
||||
Ok(
|
||||
#[cfg(unix)]
|
||||
Some(yazi_shared::fs::permissions(_me.mode, _me.is_dummy())),
|
||||
#[cfg(windows)]
|
||||
None::<String>,
|
||||
)
|
||||
});
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
#[inline]
|
||||
fn parse_time(f: Option<f64>) -> mlua::Result<Option<SystemTime>> {
|
||||
Ok(match f {
|
||||
Some(n) if n >= 0.0 => Some(SystemTime::UNIX_EPOCH + Duration::from_secs_f64(n)),
|
||||
Some(n) => Err(format!("Invalid timestamp: {n}").into_lua_err())?,
|
||||
None => None,
|
||||
})
|
||||
}
|
||||
|
||||
lua.globals().raw_set(
|
||||
"Cha",
|
||||
lua.create_function(|lua, t: Table| {
|
||||
let kind =
|
||||
ChaKind::from_bits(t.raw_get("kind")?).ok_or_else(|| "Invalid kind".into_lua_err())?;
|
||||
|
||||
Self::cast(lua, yazi_shared::fs::Cha {
|
||||
kind,
|
||||
len: t.raw_get("len").unwrap_or_default(),
|
||||
atime: parse_time(t.raw_get("atime").ok())?,
|
||||
btime: parse_time(t.raw_get("btime").ok())?,
|
||||
#[cfg(unix)]
|
||||
ctime: parse_time(t.raw_get("ctime").ok())?,
|
||||
mtime: parse_time(t.raw_get("mtime").ok())?,
|
||||
#[cfg(unix)]
|
||||
mode: t.raw_get("mode").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
uid: t.raw_get("uid").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
gid: t.raw_get("gid").unwrap_or_default(),
|
||||
#[cfg(unix)]
|
||||
nlink: t.raw_get("nlink").unwrap_or_default(),
|
||||
})
|
||||
})?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<yazi_shared::fs::Cha>> Cast<T> for Cha {
|
||||
fn cast(lua: &Lua, data: T) -> mlua::Result<AnyUserData> { lua.create_any_userdata(data.into()) }
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
use mlua::Lua;
|
||||
|
||||
yazi_macro::mod_flat!(cha);
|
||||
|
||||
pub fn pour(lua: &Lua) -> mlua::Result<()> {
|
||||
cha::Cha::register(lua)?;
|
||||
cha::Cha::install(lua)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -13,7 +13,7 @@ pub struct Bar {
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, direction): (Table, u8)| {
|
||||
Ok(Self { direction: Borders::from_bits_truncate(direction), ..Default::default() })
|
||||
})?;
|
||||
@ -29,8 +29,7 @@ impl Bar {
|
||||
])?;
|
||||
|
||||
bar.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Bar", bar)
|
||||
Ok(bar)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ pub struct Border {
|
||||
}
|
||||
|
||||
impl Border {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, position): (Table, u8)| {
|
||||
Ok(Border {
|
||||
position: ratatui::widgets::Borders::from_bits_truncate(position),
|
||||
@ -47,8 +47,7 @@ impl Border {
|
||||
])?;
|
||||
|
||||
border.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Border", border)
|
||||
Ok(border)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,13 +13,13 @@ pub struct Clear {
|
||||
}
|
||||
|
||||
impl Clear {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, area): (Table, Rect)| Ok(Clear { area }))?;
|
||||
|
||||
let clear = lua.create_table()?;
|
||||
clear.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Clear", clear)
|
||||
Ok(clear)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,17 @@ use mlua::{FromLua, Lua, Table, UserData};
|
||||
pub struct Constraint(pub(super) ratatui::layout::Constraint);
|
||||
|
||||
impl Constraint {
|
||||
pub fn install(_: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
ui.raw_set("Constraint", Constraint::default())
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
use ratatui::layout::Constraint as C;
|
||||
|
||||
lua.create_table_from([
|
||||
("Min", lua.create_function(|_, n: u16| Ok(Self(C::Min(n))))?),
|
||||
("Max", lua.create_function(|_, n: u16| Ok(Self(C::Max(n))))?),
|
||||
("Length", lua.create_function(|_, n: u16| Ok(Self(C::Length(n))))?),
|
||||
("Percentage", lua.create_function(|_, n: u16| Ok(Self(C::Percentage(n))))?),
|
||||
("Ratio", lua.create_function(|_, (a, b): (u32, u32)| Ok(Self(C::Ratio(a, b))))?),
|
||||
("Fill", lua.create_function(|_, n: u16| Ok(Self(C::Fill(n))))?),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,15 +22,4 @@ impl From<Constraint> for ratatui::layout::Constraint {
|
||||
fn from(value: Constraint) -> Self { value.0 }
|
||||
}
|
||||
|
||||
impl UserData for Constraint {
|
||||
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
|
||||
use ratatui::layout::Constraint as C;
|
||||
|
||||
methods.add_function("Min", |_, n: u16| Ok(Self(C::Min(n))));
|
||||
methods.add_function("Max", |_, n: u16| Ok(Self(C::Max(n))));
|
||||
methods.add_function("Length", |_, n: u16| Ok(Self(C::Length(n))));
|
||||
methods.add_function("Percentage", |_, n: u16| Ok(Self(C::Percentage(n))));
|
||||
methods.add_function("Ratio", |_, (a, b): (u32, u32)| Ok(Self(C::Ratio(a, b))));
|
||||
methods.add_function("Fill", |_, n: u16| Ok(Self(C::Fill(n))));
|
||||
}
|
||||
}
|
||||
impl UserData for Constraint {}
|
||||
|
@ -1,31 +1,40 @@
|
||||
use mlua::{AnyUserData, Lua, Table};
|
||||
use mlua::{AnyUserData, IntoLua, Lua, Table, Value};
|
||||
use tracing::error;
|
||||
|
||||
use crate::cast_to_renderable;
|
||||
|
||||
pub fn pour(lua: &Lua) -> mlua::Result<()> {
|
||||
let ui = lua.create_table()?;
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let index = lua.create_function(|lua, (ts, key): (Table, mlua::String)| {
|
||||
let value = match key.as_bytes().as_ref() {
|
||||
b"Bar" => super::Bar::compose(lua)?,
|
||||
b"Border" => super::Border::compose(lua)?,
|
||||
b"Clear" => super::Clear::compose(lua)?,
|
||||
b"Constraint" => super::Constraint::compose(lua)?,
|
||||
b"Gauge" => super::Gauge::compose(lua)?,
|
||||
b"Layout" => super::Layout::compose(lua)?,
|
||||
b"Line" => super::Line::compose(lua)?,
|
||||
b"List" => super::List::compose(lua)?,
|
||||
b"Padding" => super::Padding::compose(lua)?,
|
||||
b"Paragraph" => super::Paragraph::compose(lua)?,
|
||||
b"Position" => super::Position::compose(lua)?,
|
||||
b"Rect" => super::Rect::compose(lua)?,
|
||||
b"Span" => super::Span::compose(lua)?,
|
||||
b"Style" => super::Style::compose(lua)?,
|
||||
b"Table" => super::Table::compose(lua)?,
|
||||
b"TableRow" => super::TableRow::compose(lua)?,
|
||||
b"Text" => super::Text::compose(lua)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)?;
|
||||
|
||||
// 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)?;
|
||||
super::Line::install(lua, &ui)?;
|
||||
super::List::install(lua, &ui)?;
|
||||
super::Padding::install(lua, &ui)?;
|
||||
super::Paragraph::install(lua, &ui)?;
|
||||
super::Position::install(lua, &ui)?;
|
||||
super::Rect::install(lua, &ui)?;
|
||||
super::Span::install(lua, &ui)?;
|
||||
super::Style::install(lua, &ui)?;
|
||||
super::Table::install(lua, &ui)?;
|
||||
super::TableRow::install(lua, &ui)?;
|
||||
super::Text::install(lua, &ui)?;
|
||||
ts.raw_set(key, value.clone())?;
|
||||
Ok(value)
|
||||
})?;
|
||||
|
||||
lua.globals().raw_set("ui", ui)
|
||||
let ui = lua.create_table_with_capacity(0, 20)?;
|
||||
ui.set_metatable(Some(lua.create_table_from([("__index", index)])?));
|
||||
|
||||
Ok(ui)
|
||||
}
|
||||
|
||||
pub trait Renderable {
|
||||
|
@ -15,8 +15,13 @@ pub struct Gauge {
|
||||
}
|
||||
|
||||
impl Gauge {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
ui.raw_set("Gauge", lua.create_function(|_, ()| Ok(Gauge::default()))?)
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, _: Table| Ok(Gauge::default()))?;
|
||||
|
||||
let gauge = lua.create_table()?;
|
||||
gauge.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
Ok(gauge)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,14 +13,13 @@ pub struct Layout {
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, _: Table| Ok(Self::default()))?;
|
||||
|
||||
let layout = lua.create_table_from([("HORIZONTAL", HORIZONTAL), ("VERTICAL", VERTICAL)])?;
|
||||
|
||||
layout.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Layout", layout)
|
||||
Ok(layout)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ const EXPECTED: &str = "expected a string, ui.Span, ui.Line, or a table of them"
|
||||
pub struct Line(pub(super) ratatui::text::Line<'static>);
|
||||
|
||||
impl Line {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, value): (Table, Value)| Line::try_from(value))?;
|
||||
|
||||
let parse = lua.create_function(|_, code: mlua::String| {
|
||||
@ -42,8 +42,7 @@ impl Line {
|
||||
])?;
|
||||
|
||||
line.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Line", line)
|
||||
Ok(line)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,21 +12,23 @@ pub struct List {
|
||||
}
|
||||
|
||||
impl List {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
ui.raw_set(
|
||||
"List",
|
||||
lua.create_function(|_, tb: Table| {
|
||||
let mut items = Vec::with_capacity(tb.raw_len());
|
||||
for v in tb.sequence_values::<Value>() {
|
||||
match v? {
|
||||
Value::Table(_) => Err("Nested table not supported".into_lua_err())?,
|
||||
v => items.push(Text::try_from(v)?),
|
||||
}
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, seq): (Table, Table)| {
|
||||
let mut items = Vec::with_capacity(seq.raw_len());
|
||||
for v in seq.sequence_values::<Value>() {
|
||||
match v? {
|
||||
Value::Table(_) => Err("Nested table not supported".into_lua_err())?,
|
||||
v => items.push(Text::try_from(v)?),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self { inner: ratatui::widgets::List::new(items), ..Default::default() })
|
||||
})?,
|
||||
)
|
||||
Ok(Self { inner: ratatui::widgets::List::new(items), ..Default::default() })
|
||||
})?;
|
||||
|
||||
let list = lua.create_table()?;
|
||||
list.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ impl Deref for Padding {
|
||||
}
|
||||
|
||||
impl Padding {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new =
|
||||
lua.create_function(|_, (_, left, right, top, bottom): (Table, u16, u16, u16, u16)| {
|
||||
Ok(Self(ratatui::widgets::Padding::new(left, right, top, bottom)))
|
||||
@ -43,8 +43,7 @@ impl Padding {
|
||||
])?;
|
||||
|
||||
padding.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Padding", padding)
|
||||
Ok(padding)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ Please use the new `ui.Text` instead, in your {id}. See #1772 for details: https
|
||||
pub struct Paragraph;
|
||||
|
||||
impl Paragraph {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let mt = lua.create_table_from([
|
||||
(
|
||||
"__call",
|
||||
@ -60,6 +60,6 @@ impl Paragraph {
|
||||
let paragraph = lua.create_table()?;
|
||||
paragraph.set_metatable(Some(mt));
|
||||
|
||||
ui.raw_set("Paragraph", paragraph)
|
||||
Ok(paragraph)
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ impl From<ratatui::layout::Rect> for Position {
|
||||
}
|
||||
|
||||
impl Position {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, args): (Table, Table)| {
|
||||
Ok(Self(ratatui::layout::Position { x: args.raw_get("x")?, y: args.raw_get("y")? }))
|
||||
})?;
|
||||
@ -24,8 +24,7 @@ impl Position {
|
||||
let position = lua.create_table_from([("default", Self(Default::default()))])?;
|
||||
|
||||
position.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Position", position)
|
||||
Ok(position)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ impl From<ratatui::layout::Size> for Rect {
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, args): (Table, Table)| {
|
||||
Ok(Self(ratatui::layout::Rect {
|
||||
x: args.raw_get("x")?,
|
||||
@ -37,8 +37,7 @@ impl Rect {
|
||||
let rect = lua.create_table_from([("default", Self(ratatui::layout::Rect::default()))])?;
|
||||
|
||||
rect.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Rect", rect)
|
||||
Ok(rect)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,13 @@ const EXPECTED: &str = "expected a string or ui.Span";
|
||||
pub struct Span(pub(super) ratatui::text::Span<'static>);
|
||||
|
||||
impl Span {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
ui.raw_set("Span", lua.create_function(|_, value: Value| Span::try_from(value))?)
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, value): (Table, Value)| Span::try_from(value))?;
|
||||
|
||||
let span = lua.create_table()?;
|
||||
span.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
Ok(span)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,13 @@ use yazi_shared::theme::Color;
|
||||
pub struct Style(pub(super) ratatui::style::Style);
|
||||
|
||||
impl Style {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, value): (Table, Value)| Self::try_from(value))?;
|
||||
|
||||
let style = lua.create_table()?;
|
||||
style.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Style", style)
|
||||
Ok(style)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,13 +25,15 @@ pub struct Table {
|
||||
}
|
||||
|
||||
impl Table {
|
||||
pub fn install(lua: &Lua, ui: &mlua::Table) -> mlua::Result<()> {
|
||||
ui.raw_set(
|
||||
"Table",
|
||||
lua.create_function(|_, (area, rows): (Rect, Vec<TableRow>)| {
|
||||
Ok(Self { area, rows: rows.into_iter().map(Into::into).collect(), ..Default::default() })
|
||||
})?,
|
||||
)
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<mlua::Table> {
|
||||
let new = lua.create_function(|_, (_, area, rows): (mlua::Table, Rect, Vec<TableRow>)| {
|
||||
Ok(Self { area, rows: rows.into_iter().map(Into::into).collect(), ..Default::default() })
|
||||
})?;
|
||||
|
||||
let table = lua.create_table()?;
|
||||
table.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
Ok(table)
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,13 +95,15 @@ pub struct TableRow {
|
||||
}
|
||||
|
||||
impl TableRow {
|
||||
pub fn install(lua: &Lua, ui: &mlua::Table) -> mlua::Result<()> {
|
||||
ui.raw_set(
|
||||
"TableRow",
|
||||
lua.create_function(|_, cols: Vec<Text>| {
|
||||
Ok(Self { cells: cols.into_iter().map(Into::into).collect(), ..Default::default() })
|
||||
})?,
|
||||
)
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<mlua::Table> {
|
||||
let new = lua.create_function(|_, (_, cols): (mlua::Table, Vec<Text>)| {
|
||||
Ok(Self { cells: cols.into_iter().map(Into::into).collect(), ..Default::default() })
|
||||
})?;
|
||||
|
||||
let row = lua.create_table()?;
|
||||
row.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
Ok(row)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ pub struct Text {
|
||||
}
|
||||
|
||||
impl Text {
|
||||
pub fn install(lua: &Lua, ui: &Table) -> mlua::Result<()> {
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let new = lua.create_function(|_, (_, value): (Table, Value)| Text::try_from(value))?;
|
||||
|
||||
let parse = lua.create_function(|_, code: mlua::String| {
|
||||
@ -47,8 +47,7 @@ impl Text {
|
||||
])?;
|
||||
|
||||
text.set_metatable(Some(lua.create_table_from([("__call", new)])?));
|
||||
|
||||
ui.raw_set("Text", text)
|
||||
Ok(text)
|
||||
}
|
||||
}
|
||||
|
||||
|
35
yazi-plugin/src/external/highlighter.rs
vendored
35
yazi-plugin/src/external/highlighter.rs
vendored
@ -1,14 +1,14 @@
|
||||
use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}};
|
||||
use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}, sync::OnceLock};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use ratatui::{layout::Rect, text::{Line, Span, Text}};
|
||||
use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}};
|
||||
use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}, sync::OnceCell};
|
||||
use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}};
|
||||
use yazi_config::{PREVIEW, THEME, preview::PreviewWrap};
|
||||
use yazi_shared::{Ids, errors::PeekError, replace_to_printable};
|
||||
|
||||
static INCR: Ids = Ids::new();
|
||||
static SYNTECT: OnceCell<(Theme, SyntaxSet)> = OnceCell::const_new();
|
||||
static SYNTECT: OnceLock<(Theme, SyntaxSet)> = OnceLock::new();
|
||||
|
||||
pub struct Highlighter {
|
||||
path: PathBuf,
|
||||
@ -18,24 +18,19 @@ impl Highlighter {
|
||||
#[inline]
|
||||
pub fn new(path: &Path) -> Self { Self { path: path.to_owned() } }
|
||||
|
||||
pub async fn init() -> (&'static Theme, &'static SyntaxSet) {
|
||||
let fut = async {
|
||||
tokio::task::spawn_blocking(|| {
|
||||
let theme = std::fs::File::open(&THEME.manager.syntect_theme)
|
||||
.map_err(LoadingError::Io)
|
||||
.and_then(|f| ThemeSet::load_from_reader(&mut std::io::BufReader::new(f)))
|
||||
.or_else(|_| ThemeSet::load_from_reader(&mut Cursor::new(yazi_prebuild::ansi_theme())));
|
||||
pub fn init() -> (&'static Theme, &'static SyntaxSet) {
|
||||
let r = SYNTECT.get_or_init(|| {
|
||||
let theme = std::fs::File::open(&THEME.manager.syntect_theme)
|
||||
.map_err(LoadingError::Io)
|
||||
.and_then(|f| ThemeSet::load_from_reader(&mut std::io::BufReader::new(f)))
|
||||
.or_else(|_| ThemeSet::load_from_reader(&mut Cursor::new(yazi_prebuild::ansi_theme())));
|
||||
|
||||
let syntaxes = dumps::from_uncompressed_data(yazi_prebuild::syntaxes());
|
||||
let syntaxes = dumps::from_uncompressed_data(yazi_prebuild::syntaxes());
|
||||
|
||||
(theme.unwrap(), syntaxes.unwrap())
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
};
|
||||
(theme.unwrap(), syntaxes.unwrap())
|
||||
});
|
||||
|
||||
let (theme, syntaxes) = SYNTECT.get_or_init(|| fut).await;
|
||||
(theme, syntaxes)
|
||||
(&r.0, &r.1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -105,7 +100,7 @@ impl Highlighter {
|
||||
syntax: &'static SyntaxReference,
|
||||
) -> Result<Text<'static>, PeekError> {
|
||||
let ticket = INCR.current();
|
||||
let (theme, syntaxes) = Self::init().await;
|
||||
let (theme, syntaxes) = Self::init();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let mut h = HighlightLines::new(syntax, theme);
|
||||
@ -133,7 +128,7 @@ impl Highlighter {
|
||||
}
|
||||
|
||||
async fn find_syntax(path: &Path) -> Result<&'static SyntaxReference> {
|
||||
let (_, syntaxes) = Self::init().await;
|
||||
let (_, syntaxes) = Self::init();
|
||||
let name = path.file_name().map(|n| n.to_string_lossy()).unwrap_or_default();
|
||||
if let Some(s) = syntaxes.find_syntax_by_extension(&name) {
|
||||
return Ok(s);
|
||||
|
@ -1,122 +1,134 @@
|
||||
use globset::GlobBuilder;
|
||||
use mlua::{ExternalError, ExternalResult, IntoLuaMulti, Lua, Table, Value};
|
||||
use mlua::{ExternalError, ExternalResult, Function, IntoLua, IntoLuaMulti, Lua, Table, Value};
|
||||
use tokio::fs;
|
||||
use yazi_shared::fs::remove_dir_clean;
|
||||
|
||||
use crate::{bindings::Cast, cha::Cha, file::File, url::{Url, UrlRef}};
|
||||
use crate::{bindings::{Cast, Cha}, file::File, url::{Url, UrlRef}};
|
||||
|
||||
pub fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
lua.globals().raw_set(
|
||||
"fs",
|
||||
lua.create_table_from([
|
||||
(
|
||||
"cha",
|
||||
lua.create_async_function(|lua, (url, follow): (UrlRef, Option<bool>)| async move {
|
||||
let meta = if follow.unwrap_or(false) {
|
||||
fs::metadata(&*url).await
|
||||
} else {
|
||||
fs::symlink_metadata(&*url).await
|
||||
};
|
||||
pub fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let index = lua.create_function(|lua, (ts, key): (Table, mlua::String)| {
|
||||
let value = match key.as_bytes().as_ref() {
|
||||
b"cha" => cha(lua)?,
|
||||
b"write" => write(lua)?,
|
||||
b"remove" => remove(lua)?,
|
||||
b"read_dir" => read_dir(lua)?,
|
||||
b"unique_name" => unique_name(lua)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)?;
|
||||
|
||||
match meta {
|
||||
Ok(m) => (Cha::cast(&lua, m)?, Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})?,
|
||||
),
|
||||
(
|
||||
"write",
|
||||
lua.create_async_function(|lua, (url, data): (UrlRef, mlua::String)| async move {
|
||||
match fs::write(&*url, data.as_bytes()).await {
|
||||
Ok(_) => (true, Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (false, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})?,
|
||||
),
|
||||
(
|
||||
"remove",
|
||||
lua.create_async_function(|lua, (type_, url): (mlua::String, UrlRef)| async move {
|
||||
let result = match &*type_.to_str()? {
|
||||
"file" => fs::remove_file(&*url).await,
|
||||
"dir" => fs::remove_dir(&*url).await,
|
||||
"dir_all" => fs::remove_dir_all(&*url).await,
|
||||
"dir_clean" => Ok(remove_dir_clean(&url).await),
|
||||
_ => {
|
||||
Err("Removal type must be 'file', 'dir', 'dir_all', or 'dir_clean'".into_lua_err())?
|
||||
}
|
||||
};
|
||||
ts.raw_set(key, value.clone())?;
|
||||
Ok(value)
|
||||
})?;
|
||||
|
||||
match result {
|
||||
Ok(_) => (true, Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (false, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})?,
|
||||
),
|
||||
(
|
||||
"read_dir",
|
||||
lua.create_async_function(|lua, (dir, options): (UrlRef, Table)| async move {
|
||||
let glob = if let Ok(s) = options.raw_get::<mlua::String>("glob") {
|
||||
Some(
|
||||
GlobBuilder::new(&s.to_str()?)
|
||||
.case_insensitive(true)
|
||||
.literal_separator(true)
|
||||
.backslash_escape(false)
|
||||
.empty_alternates(true)
|
||||
.build()
|
||||
.into_lua_err()?
|
||||
.compile_matcher(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let fs = lua.create_table_with_capacity(0, 10)?;
|
||||
fs.set_metatable(Some(lua.create_table_from([("__index", index)])?));
|
||||
|
||||
let limit = options.raw_get("limit").unwrap_or(usize::MAX);
|
||||
let resolve = options.raw_get("resolve").unwrap_or(false);
|
||||
|
||||
let mut it = match fs::read_dir(&*dir).await {
|
||||
Ok(it) => it,
|
||||
Err(e) => return (Value::Nil, e.raw_os_error()).into_lua_multi(&lua),
|
||||
};
|
||||
|
||||
let mut files = vec![];
|
||||
while let Ok(Some(next)) = it.next_entry().await {
|
||||
if files.len() >= limit {
|
||||
break;
|
||||
}
|
||||
|
||||
let path = next.path();
|
||||
if glob.as_ref().is_some_and(|g| !g.is_match(&path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let url = yazi_shared::fs::Url::from(path);
|
||||
let file = if !resolve {
|
||||
yazi_shared::fs::File::from_dummy(url, next.file_type().await.ok())
|
||||
} else if let Ok(meta) = next.metadata().await {
|
||||
yazi_shared::fs::File::from_meta(url, meta).await
|
||||
} else {
|
||||
yazi_shared::fs::File::from_dummy(url, next.file_type().await.ok())
|
||||
};
|
||||
files.push(File::cast(&lua, file)?);
|
||||
}
|
||||
|
||||
let tbl = lua.create_table_with_capacity(files.len(), 0)?;
|
||||
for f in files {
|
||||
tbl.raw_push(f)?;
|
||||
}
|
||||
|
||||
(tbl, Value::Nil).into_lua_multi(&lua)
|
||||
})?,
|
||||
),
|
||||
(
|
||||
"unique_name",
|
||||
lua.create_async_function(|lua, url: UrlRef| async move {
|
||||
match yazi_shared::fs::unique_name(url.clone(), async { false }).await {
|
||||
Ok(u) => (Url::cast(&lua, u)?, Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})?,
|
||||
),
|
||||
])?,
|
||||
)
|
||||
Ok(fs)
|
||||
}
|
||||
|
||||
fn cha(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (url, follow): (UrlRef, Option<bool>)| async move {
|
||||
let meta = if follow.unwrap_or(false) {
|
||||
fs::metadata(&*url).await
|
||||
} else {
|
||||
fs::symlink_metadata(&*url).await
|
||||
};
|
||||
|
||||
match meta {
|
||||
Ok(m) => (Cha::from(m), Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn write(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (url, data): (UrlRef, mlua::String)| async move {
|
||||
match fs::write(&*url, data.as_bytes()).await {
|
||||
Ok(_) => (true, Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (false, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn remove(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (type_, url): (mlua::String, UrlRef)| async move {
|
||||
let result = match &*type_.to_str()? {
|
||||
"file" => fs::remove_file(&*url).await,
|
||||
"dir" => fs::remove_dir(&*url).await,
|
||||
"dir_all" => fs::remove_dir_all(&*url).await,
|
||||
"dir_clean" => Ok(remove_dir_clean(&url).await),
|
||||
_ => Err("Removal type must be 'file', 'dir', 'dir_all', or 'dir_clean'".into_lua_err())?,
|
||||
};
|
||||
|
||||
match result {
|
||||
Ok(_) => (true, Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (false, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn read_dir(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (dir, options): (UrlRef, Table)| async move {
|
||||
let glob = if let Ok(s) = options.raw_get::<mlua::String>("glob") {
|
||||
Some(
|
||||
GlobBuilder::new(&s.to_str()?)
|
||||
.case_insensitive(true)
|
||||
.literal_separator(true)
|
||||
.backslash_escape(false)
|
||||
.empty_alternates(true)
|
||||
.build()
|
||||
.into_lua_err()?
|
||||
.compile_matcher(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let limit = options.raw_get("limit").unwrap_or(usize::MAX);
|
||||
let resolve = options.raw_get("resolve").unwrap_or(false);
|
||||
|
||||
let mut it = match fs::read_dir(&*dir).await {
|
||||
Ok(it) => it,
|
||||
Err(e) => return (Value::Nil, e.raw_os_error()).into_lua_multi(&lua),
|
||||
};
|
||||
|
||||
let mut files = vec![];
|
||||
while let Ok(Some(next)) = it.next_entry().await {
|
||||
if files.len() >= limit {
|
||||
break;
|
||||
}
|
||||
|
||||
let path = next.path();
|
||||
if glob.as_ref().is_some_and(|g| !g.is_match(&path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let url = yazi_shared::fs::Url::from(path);
|
||||
let file = if !resolve {
|
||||
yazi_shared::fs::File::from_dummy(url, next.file_type().await.ok())
|
||||
} else if let Ok(meta) = next.metadata().await {
|
||||
yazi_shared::fs::File::from_meta(url, meta).await
|
||||
} else {
|
||||
yazi_shared::fs::File::from_dummy(url, next.file_type().await.ok())
|
||||
};
|
||||
files.push(File::cast(&lua, file)?);
|
||||
}
|
||||
|
||||
let tbl = lua.create_table_with_capacity(files.len(), 0)?;
|
||||
for f in files {
|
||||
tbl.raw_push(f)?;
|
||||
}
|
||||
|
||||
(tbl, Value::Nil).into_lua_multi(&lua)
|
||||
})
|
||||
}
|
||||
|
||||
fn unique_name(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, url: UrlRef| async move {
|
||||
match yazi_shared::fs::unique_name(url.clone(), async { false }).await {
|
||||
Ok(u) => (Url::cast(&lua, u)?, Value::Nil).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, e.raw_os_error()).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,33 +1,28 @@
|
||||
use mlua::Lua;
|
||||
use yazi_macro::plugin_preset as preset;
|
||||
|
||||
use crate::{elements, runtime::Runtime};
|
||||
use crate::runtime::Runtime;
|
||||
|
||||
pub fn slim_lua(name: &str) -> mlua::Result<Lua> {
|
||||
let lua = Lua::new();
|
||||
lua.set_named_registry_value("rt", Runtime::new(name))?;
|
||||
crate::Config::new(&lua).install_preview()?;
|
||||
|
||||
// Base
|
||||
crate::bindings::Icon::register(&lua)?;
|
||||
crate::cha::pour(&lua)?;
|
||||
let globals = lua.globals();
|
||||
globals.raw_set("ui", crate::elements::compose(&lua)?)?;
|
||||
globals.raw_set("ya", crate::utils::compose(&lua, true)?)?;
|
||||
globals.raw_set("fs", crate::fs::compose(&lua)?)?;
|
||||
|
||||
crate::bindings::Cha::install(&lua)?;
|
||||
crate::file::pour(&lua)?;
|
||||
crate::url::pour(&lua)?;
|
||||
|
||||
crate::loader::install_isolate(&lua)?;
|
||||
crate::fs::install(&lua)?;
|
||||
crate::process::install(&lua)?;
|
||||
crate::utils::install_isolate(&lua)?;
|
||||
crate::Config::new(&lua).install_preview()?;
|
||||
|
||||
// Addons
|
||||
lua.load(preset!("ya")).set_name("ya.lua").exec()?;
|
||||
|
||||
// Elements
|
||||
let ui = lua.create_table()?;
|
||||
elements::Line::install(&lua, &ui)?;
|
||||
elements::Paragraph::install(&lua, &ui)?;
|
||||
elements::Rect::install(&lua, &ui)?;
|
||||
elements::Span::install(&lua, &ui)?;
|
||||
elements::Text::install(&lua, &ui)?;
|
||||
|
||||
lua.globals().raw_set("ui", ui)?;
|
||||
Ok(lua)
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
mod macros;
|
||||
|
||||
yazi_macro::mod_pub!(
|
||||
bindings, cha, elements, external, file, fs, isolate, loader, process, pubsub, url, utils
|
||||
bindings, elements, external, file, fs, isolate, loader, process, pubsub, url, utils
|
||||
);
|
||||
|
||||
yazi_macro::mod_flat!(cast clipboard config lua runtime);
|
||||
|
@ -17,21 +17,23 @@ pub(super) fn init_lua() -> Result<()> {
|
||||
}
|
||||
|
||||
fn stage_1(lua: &'static Lua) -> Result<()> {
|
||||
lua.set_named_registry_value("rt", Runtime::default())?;
|
||||
crate::Config::new(lua).install_boot()?.install_manager()?.install_theme()?;
|
||||
crate::utils::install(lua)?;
|
||||
|
||||
// Base
|
||||
lua.set_named_registry_value("rt", Runtime::default())?;
|
||||
lua.load(preset!("ya")).set_name("ya.lua").exec()?;
|
||||
crate::bindings::Icon::register(lua)?;
|
||||
crate::bindings::MouseEvent::register(lua)?;
|
||||
crate::elements::pour(lua)?;
|
||||
let globals = lua.globals();
|
||||
globals.raw_set("ui", crate::elements::compose(lua)?)?;
|
||||
globals.raw_set("ya", crate::utils::compose(lua, false)?)?;
|
||||
globals.raw_set("ps", crate::pubsub::compose(lua)?)?;
|
||||
|
||||
crate::bindings::Cha::install(lua)?;
|
||||
crate::loader::install(lua)?;
|
||||
crate::pubsub::install(lua)?;
|
||||
crate::cha::pour(lua)?;
|
||||
crate::file::pour(lua)?;
|
||||
crate::url::pour(lua)?;
|
||||
|
||||
// Addons
|
||||
lua.load(preset!("ya")).set_name("ya.lua").exec()?;
|
||||
|
||||
// Components
|
||||
lua.load(preset!("components/current")).set_name("current.lua").exec()?;
|
||||
lua.load(preset!("components/entity")).set_name("entity.lua").exec()?;
|
||||
|
@ -85,7 +85,7 @@ macro_rules! impl_file_fields {
|
||||
use mlua::UserDataFields;
|
||||
use $crate::bindings::Cast;
|
||||
|
||||
$fields.add_field_method_get("cha", |lua, me| $crate::cha::Cha::cast(lua, me.cha));
|
||||
$fields.add_field_method_get("cha", |_, me| Ok($crate::bindings::Cha::from(me.cha)));
|
||||
$fields.add_field_method_get("url", |lua, me| $crate::url::Url::cast(lua, me.url_owned()));
|
||||
$fields.add_field_method_get("link_to", |lua, me| {
|
||||
me.link_to.clone().map(|u| $crate::url::Url::cast(lua, u)).transpose()
|
||||
@ -105,19 +105,19 @@ macro_rules! impl_file_methods {
|
||||
($methods:ident) => {
|
||||
use mlua::UserDataMethods;
|
||||
|
||||
$methods.add_method("icon", |lua, me, ()| {
|
||||
$methods.add_method("icon", |_, me, ()| {
|
||||
use yazi_shared::theme::IconCache;
|
||||
use $crate::bindings::{Cast, Icon};
|
||||
use $crate::bindings::Icon;
|
||||
|
||||
match me.icon.get() {
|
||||
Ok(match me.icon.get() {
|
||||
IconCache::Missing => {
|
||||
let matched = yazi_config::THEME.icons.matches(me);
|
||||
me.icon.set(matched.map_or(IconCache::Undefined, IconCache::Icon));
|
||||
matched.map(|i| Icon::cast(lua, i)).transpose()
|
||||
matched.map(Icon::from)
|
||||
}
|
||||
IconCache::Undefined => Ok(None),
|
||||
IconCache::Icon(cached) => Some(Icon::cast(lua, cached)).transpose(),
|
||||
}
|
||||
IconCache::Undefined => None,
|
||||
IconCache::Icon(cached) => Some(Icon::from(cached)),
|
||||
})
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -1,11 +1,28 @@
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
use mlua::Lua;
|
||||
use mlua::{IntoLua, Lua, Table, Value};
|
||||
|
||||
yazi_macro::mod_flat!(pubsub);
|
||||
|
||||
pub(super) fn install(lua: &'static Lua) -> mlua::Result<()> {
|
||||
Pubsub::install(lua)?;
|
||||
pub(super) fn compose(lua: &Lua) -> mlua::Result<Table> {
|
||||
let index = lua.create_function(|lua, (ts, key): (Table, mlua::String)| {
|
||||
let value = match key.as_bytes().as_ref() {
|
||||
b"pub" => Pubsub::pub_(lua)?,
|
||||
b"pub_to" => Pubsub::pub_to(lua)?,
|
||||
b"sub" => Pubsub::sub(lua)?,
|
||||
b"sub_remote" => Pubsub::sub_remote(lua)?,
|
||||
b"unsub" => Pubsub::unsub(lua)?,
|
||||
b"unsub_remote" => Pubsub::unsub_remote(lua)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)?;
|
||||
|
||||
Ok(())
|
||||
ts.raw_set(key, value.clone())?;
|
||||
Ok(value)
|
||||
})?;
|
||||
|
||||
let ps = lua.create_table_with_capacity(0, 10)?;
|
||||
ps.set_metatable(Some(lua.create_table_from([("__index", index)])?));
|
||||
|
||||
Ok(ps)
|
||||
}
|
||||
|
@ -6,75 +6,63 @@ use crate::runtime::RtRef;
|
||||
pub struct Pubsub;
|
||||
|
||||
impl Pubsub {
|
||||
pub(super) fn install(lua: &'static Lua) -> mlua::Result<()> {
|
||||
let ps = lua.create_table()?;
|
||||
pub(super) fn pub_(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, (kind, value): (mlua::String, Value)| {
|
||||
yazi_dds::Pubsub::pub_(Body::from_lua(&kind.to_str()?, value)?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
ps.raw_set(
|
||||
"pub",
|
||||
lua.create_function(|_, (kind, value): (mlua::String, Value)| {
|
||||
yazi_dds::Pubsub::pub_(Body::from_lua(&kind.to_str()?, value)?);
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
pub(super) fn pub_to(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, (receiver, kind, value): (u64, mlua::String, Value)| {
|
||||
yazi_dds::Pubsub::pub_to(receiver, Body::from_lua(&kind.to_str()?, value)?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
ps.raw_set(
|
||||
"pub_to",
|
||||
lua.create_function(|_, (receiver, kind, value): (u64, mlua::String, Value)| {
|
||||
yazi_dds::Pubsub::pub_to(receiver, Body::from_lua(&kind.to_str()?, value)?);
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
pub(super) fn sub(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, (kind, f): (mlua::String, Function)| {
|
||||
let rt = lua.named_registry_value::<RtRef>("rt")?;
|
||||
let Some(cur) = rt.current() else {
|
||||
return Err("`sub()` must be called in a sync plugin").into_lua_err();
|
||||
};
|
||||
if !yazi_dds::Pubsub::sub(cur, &kind.to_str()?, f) {
|
||||
return Err("`sub()` called twice").into_lua_err();
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
ps.raw_set(
|
||||
"sub",
|
||||
lua.create_function(|lua, (kind, f): (mlua::String, Function)| {
|
||||
let rt = lua.named_registry_value::<RtRef>("rt")?;
|
||||
let Some(cur) = rt.current() else {
|
||||
return Err("`sub()` must be called in a sync plugin").into_lua_err();
|
||||
};
|
||||
if !yazi_dds::Pubsub::sub(cur, &kind.to_str()?, f) {
|
||||
return Err("`sub()` called twice").into_lua_err();
|
||||
}
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
pub(super) fn sub_remote(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, (kind, f): (mlua::String, Function)| {
|
||||
let rt = lua.named_registry_value::<RtRef>("rt")?;
|
||||
let Some(cur) = rt.current() else {
|
||||
return Err("`sub_remote()` must be called in a sync plugin").into_lua_err();
|
||||
};
|
||||
if !yazi_dds::Pubsub::sub_remote(cur, &kind.to_str()?, f) {
|
||||
return Err("`sub_remote()` called twice").into_lua_err();
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
ps.raw_set(
|
||||
"sub_remote",
|
||||
lua.create_function(|_, (kind, f): (mlua::String, Function)| {
|
||||
let rt = lua.named_registry_value::<RtRef>("rt")?;
|
||||
let Some(cur) = rt.current() else {
|
||||
return Err("`sub_remote()` must be called in a sync plugin").into_lua_err();
|
||||
};
|
||||
if !yazi_dds::Pubsub::sub_remote(cur, &kind.to_str()?, f) {
|
||||
return Err("`sub_remote()` called twice").into_lua_err();
|
||||
}
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
pub(super) fn unsub(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, kind: mlua::String| {
|
||||
if let Some(cur) = lua.named_registry_value::<RtRef>("rt")?.current() {
|
||||
Ok(yazi_dds::Pubsub::unsub(cur, &kind.to_str()?))
|
||||
} else {
|
||||
Err("`unsub()` must be called in a sync plugin").into_lua_err()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ps.raw_set(
|
||||
"unsub",
|
||||
lua.create_function(|_, kind: mlua::String| {
|
||||
if let Some(cur) = lua.named_registry_value::<RtRef>("rt")?.current() {
|
||||
Ok(yazi_dds::Pubsub::unsub(cur, &kind.to_str()?))
|
||||
} else {
|
||||
Err("`unsub()` must be called in a sync plugin").into_lua_err()
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ps.raw_set(
|
||||
"unsub_remote",
|
||||
lua.create_function(|_, kind: mlua::String| {
|
||||
if let Some(cur) = lua.named_registry_value::<RtRef>("rt")?.current() {
|
||||
Ok(yazi_dds::Pubsub::unsub_remote(cur, &kind.to_str()?))
|
||||
} else {
|
||||
Err("`unsub_remote()` must be called in a sync plugin").into_lua_err()
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
|
||||
lua.globals().raw_set("ps", ps)
|
||||
pub(super) fn unsub_remote(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, kind: mlua::String| {
|
||||
if let Some(cur) = lua.named_registry_value::<RtRef>("rt")?.current() {
|
||||
Ok(yazi_dds::Pubsub::unsub_remote(cur, &kind.to_str()?))
|
||||
} else {
|
||||
Err("`unsub_remote()` must be called in a sync plugin").into_lua_err()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,21 @@
|
||||
use mlua::{AnyUserData, ExternalError, Lua, Table};
|
||||
use mlua::{AnyUserData, ExternalError, Function, Lua};
|
||||
use yazi_proxy::{AppProxy, HIDER};
|
||||
|
||||
use super::Utils;
|
||||
use crate::bindings::{Permit, PermitRef};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn app(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"hide",
|
||||
lua.create_async_function(|lua, ()| async move {
|
||||
if lua.named_registry_value::<PermitRef<fn()>>("HIDE_PERMIT").is_ok_and(|h| h.is_some()) {
|
||||
return Err("Cannot hide while already hidden".into_lua_err());
|
||||
}
|
||||
pub(super) fn hide(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, ()| async move {
|
||||
if lua.named_registry_value::<PermitRef<fn()>>("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;
|
||||
let permit = HIDER.acquire().await.unwrap();
|
||||
AppProxy::stop().await;
|
||||
|
||||
lua
|
||||
.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume as fn()))?;
|
||||
lua.named_registry_value::<AnyUserData>("HIDE_PERMIT")
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
lua.set_named_registry_value("HIDE_PERMIT", Permit::new(permit, AppProxy::resume as fn()))?;
|
||||
lua.named_registry_value::<AnyUserData>("HIDE_PERMIT")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,25 @@
|
||||
use md5::{Digest, Md5};
|
||||
use mlua::{Lua, Table};
|
||||
use mlua::{Function, Lua, Table};
|
||||
use yazi_config::PREVIEW;
|
||||
|
||||
use super::Utils;
|
||||
use crate::{bindings::Cast, file::FileRef, url::Url};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn cache(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"file_cache",
|
||||
lua.create_function(|lua, t: Table| {
|
||||
let file: FileRef = t.raw_get("file")?;
|
||||
if file.url.parent() == Some(&PREVIEW.cache_dir) {
|
||||
return Ok(None);
|
||||
}
|
||||
pub(super) fn file_cache(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, t: Table| {
|
||||
let file: FileRef = t.raw_get("file")?;
|
||||
if file.url.parent() == Some(&PREVIEW.cache_dir) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let hex = {
|
||||
let mut digest = Md5::new_with_prefix(file.url.as_os_str().as_encoded_bytes());
|
||||
digest.update(format!("//{:?}//{}", file.cha.mtime, t.raw_get("skip").unwrap_or(0)));
|
||||
format!("{:x}", digest.finalize())
|
||||
};
|
||||
let hex = {
|
||||
let mut digest = Md5::new_with_prefix(file.url.as_os_str().as_encoded_bytes());
|
||||
digest.update(format!("//{:?}//{}", file.cha.mtime, t.raw_get("skip").unwrap_or(0)));
|
||||
format!("{:x}", digest.finalize())
|
||||
};
|
||||
|
||||
Some(Url::cast(lua, PREVIEW.cache_dir.join(hex))).transpose()
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
Some(Url::cast(lua, PREVIEW.cache_dir.join(hex))).transpose()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use mlua::{ExternalError, Lua, ObjectLike, Table, Value};
|
||||
use mlua::{ExternalError, Function, Lua, ObjectLike, Table, Value};
|
||||
use tracing::error;
|
||||
use yazi_config::LAYOUT;
|
||||
use yazi_dds::Sendable;
|
||||
@ -10,6 +10,57 @@ use yazi_shared::{Layer, event::{Cmd, Data}};
|
||||
use super::Utils;
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn render(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, ()| {
|
||||
render!();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn redraw_with(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, c: Table| {
|
||||
let id: mlua::String = c.get("_id")?;
|
||||
|
||||
let mut layout = LAYOUT.get();
|
||||
match id.as_bytes().as_ref() {
|
||||
b"current" => layout.current = *c.raw_get::<crate::elements::Rect>("_area")?,
|
||||
b"preview" => layout.preview = *c.raw_get::<crate::elements::Rect>("_area")?,
|
||||
b"progress" => layout.progress = *c.raw_get::<crate::elements::Rect>("_area")?,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
LAYOUT.set(layout);
|
||||
match c.call_method::<Table>("redraw", ()) {
|
||||
Err(e) => {
|
||||
error!("Failed to `redraw()` the `{}` component:\n{e}", id.display());
|
||||
lua.create_table()
|
||||
}
|
||||
ok => ok,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn app_emit(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, (name, args): (String, Table)| {
|
||||
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::App));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn manager_emit(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, (name, args): (String, Table)| {
|
||||
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::Manager));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn input_emit(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, (name, args): (String, Table)| {
|
||||
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::Input));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_args(t: Table) -> mlua::Result<HashMap<String, Data>> {
|
||||
let mut args = HashMap::with_capacity(t.raw_len());
|
||||
for pair in t.pairs::<Value, Value>() {
|
||||
@ -26,65 +77,4 @@ impl Utils {
|
||||
}
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
pub(super) fn call(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"render",
|
||||
lua.create_function(|_, ()| {
|
||||
render!();
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"redraw_with",
|
||||
lua.create_function(|lua, c: Table| {
|
||||
let id: mlua::String = c.get("_id")?;
|
||||
let id = id.to_str()?;
|
||||
|
||||
let mut layout = LAYOUT.get();
|
||||
match id.as_ref() {
|
||||
"current" => layout.current = *c.raw_get::<crate::elements::Rect>("_area")?,
|
||||
"preview" => layout.preview = *c.raw_get::<crate::elements::Rect>("_area")?,
|
||||
"progress" => layout.progress = *c.raw_get::<crate::elements::Rect>("_area")?,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
LAYOUT.set(layout);
|
||||
match c.call_method::<Table>("redraw", ()) {
|
||||
Err(e) => {
|
||||
error!("Failed to `redraw()` the `{id}` component:\n{e}");
|
||||
lua.create_table()
|
||||
}
|
||||
ok => ok,
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"app_emit",
|
||||
lua.create_function(|_, (name, args): (String, Table)| {
|
||||
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::App));
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"manager_emit",
|
||||
lua.create_function(|_, (name, args): (String, Table)| {
|
||||
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::Manager));
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"input_emit",
|
||||
lua.create_function(|_, (name, args): (String, Table)| {
|
||||
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::Input));
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,23 @@
|
||||
use mlua::{IntoLua, Lua, Table, Value};
|
||||
use mlua::{Function, IntoLua, Lua, Value};
|
||||
use yazi_adapter::{ADAPTOR, Image};
|
||||
|
||||
use super::Utils;
|
||||
use crate::{elements::Rect, url::UrlRef};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn image(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"image_show",
|
||||
lua.create_async_function(|lua, (url, rect): (UrlRef, Rect)| async move {
|
||||
if let Ok(area) = ADAPTOR.image_show(&url, *rect).await {
|
||||
Rect::from(area).into_lua(&lua)
|
||||
} else {
|
||||
Value::Nil.into_lua(&lua)
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
pub(super) fn image_show(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (url, rect): (UrlRef, Rect)| async move {
|
||||
if let Ok(area) = ADAPTOR.image_show(&url, *rect).await {
|
||||
Rect::from(area).into_lua(&lua)
|
||||
} else {
|
||||
Value::Nil.into_lua(&lua)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ya.raw_set(
|
||||
"image_precache",
|
||||
lua.create_async_function(|_, (src, dist): (UrlRef, UrlRef)| async move {
|
||||
Ok(Image::precache(&src, dist.to_path_buf()).await.is_ok())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
pub(super) fn image_precache(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|_, (src, dist): (UrlRef, UrlRef)| async move {
|
||||
Ok(Image::precache(&src, dist.to_path_buf()).await.is_ok())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::{str::FromStr, time::Duration};
|
||||
|
||||
use mlua::{ExternalError, ExternalResult, IntoLuaMulti, Lua, Table, Value};
|
||||
use mlua::{ExternalError, ExternalResult, Function, IntoLuaMulti, Lua, Table, Value};
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
use yazi_config::{keymap::{Chord, Key}, popup::InputCfg};
|
||||
@ -12,6 +12,81 @@ use super::Utils;
|
||||
use crate::bindings::{InputRx, Position};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn which(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|_, t: Table| async move {
|
||||
let (tx, mut rx) = mpsc::channel::<usize>(1);
|
||||
|
||||
let mut cands = Vec::with_capacity(30);
|
||||
for (i, cand) in t.raw_get::<Table>("cands")?.sequence_values::<Table>().enumerate() {
|
||||
let cand = cand?;
|
||||
cands.push(Chord {
|
||||
on: Self::parse_keys(cand.raw_get("on")?)?,
|
||||
run: vec![Cmd::args("callback", &[i]).with_any("tx", tx.clone())],
|
||||
desc: cand.raw_get("desc").ok(),
|
||||
});
|
||||
}
|
||||
|
||||
drop(tx);
|
||||
emit!(Call(
|
||||
Cmd::new("show")
|
||||
.with("layer", Layer::Which)
|
||||
.with_any("candidates", cands)
|
||||
.with_bool("silent", t.raw_get("silent").unwrap_or_default()),
|
||||
Layer::Which
|
||||
));
|
||||
|
||||
Ok(rx.recv().await.map(|idx| idx + 1))
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn input(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, t: Table| async move {
|
||||
let realtime = t.raw_get("realtime").unwrap_or_default();
|
||||
let rx = UnboundedReceiverStream::new(InputProxy::show(InputCfg {
|
||||
title: t.raw_get("title")?,
|
||||
value: t.raw_get("value").unwrap_or_default(),
|
||||
cursor: None, // TODO
|
||||
position: Position::try_from(t.raw_get::<Table>("position")?)?.into(),
|
||||
realtime,
|
||||
completion: false,
|
||||
highlight: false,
|
||||
}));
|
||||
|
||||
if !realtime {
|
||||
return InputRx::consume(rx).await.into_lua_multi(&lua);
|
||||
}
|
||||
|
||||
let debounce = t.raw_get::<f64>("debounce").unwrap_or_default();
|
||||
if debounce < 0.0 {
|
||||
Err("negative debounce duration".into_lua_err())
|
||||
} else if debounce == 0.0 {
|
||||
(InputRx::new(rx), Value::Nil).into_lua_multi(&lua)
|
||||
} else {
|
||||
(InputRx::new(Debounce::new(rx, Duration::from_secs_f64(debounce))), Value::Nil)
|
||||
.into_lua_multi(&lua)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: redesign the confirm API
|
||||
// pub(super) fn confirm(lua: &Lua, ya: &Table) -> mlua::Result<Function> {
|
||||
// lua.create_async_function(|_, t: Table| async move {
|
||||
// let result = ConfirmProxy::show(ConfirmCfg {
|
||||
// title: t.raw_get("title")?,
|
||||
// content: t.raw_get("content")?,
|
||||
// position: Position::try_from(t.raw_get::<_, Table>("position")?)?.into(),
|
||||
// });
|
||||
// Ok(result.await)
|
||||
// })
|
||||
// }
|
||||
|
||||
pub(super) fn notify(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, t: Table| {
|
||||
AppProxy::notify(t.try_into()?);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_keys(value: Value) -> mlua::Result<Vec<Key>> {
|
||||
Ok(match value {
|
||||
Value::String(s) => {
|
||||
@ -27,87 +102,4 @@ impl Utils {
|
||||
_ => Err("invalid `on`".into_lua_err())?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn layer(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"which",
|
||||
lua.create_async_function(|_, t: Table| async move {
|
||||
let (tx, mut rx) = mpsc::channel::<usize>(1);
|
||||
|
||||
let mut cands = Vec::with_capacity(30);
|
||||
for (i, cand) in t.raw_get::<Table>("cands")?.sequence_values::<Table>().enumerate() {
|
||||
let cand = cand?;
|
||||
cands.push(Chord {
|
||||
on: Self::parse_keys(cand.raw_get("on")?)?,
|
||||
run: vec![Cmd::args("callback", &[i]).with_any("tx", tx.clone())],
|
||||
desc: cand.raw_get("desc").ok(),
|
||||
});
|
||||
}
|
||||
|
||||
drop(tx);
|
||||
emit!(Call(
|
||||
Cmd::new("show")
|
||||
.with("layer", Layer::Which)
|
||||
.with_any("candidates", cands)
|
||||
.with_bool("silent", t.raw_get("silent").unwrap_or_default()),
|
||||
Layer::Which
|
||||
));
|
||||
|
||||
Ok(rx.recv().await.map(|idx| idx + 1))
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"input",
|
||||
lua.create_async_function(|lua, t: Table| async move {
|
||||
let realtime = t.raw_get("realtime").unwrap_or_default();
|
||||
let rx = UnboundedReceiverStream::new(InputProxy::show(InputCfg {
|
||||
title: t.raw_get("title")?,
|
||||
value: t.raw_get("value").unwrap_or_default(),
|
||||
cursor: None, // TODO
|
||||
position: Position::try_from(t.raw_get::<Table>("position")?)?.into(),
|
||||
realtime,
|
||||
completion: false,
|
||||
highlight: false,
|
||||
}));
|
||||
|
||||
if !realtime {
|
||||
return InputRx::consume(rx).await.into_lua_multi(&lua);
|
||||
}
|
||||
|
||||
let debounce = t.raw_get::<f64>("debounce").unwrap_or_default();
|
||||
if debounce < 0.0 {
|
||||
Err("negative debounce duration".into_lua_err())
|
||||
} else if debounce == 0.0 {
|
||||
(InputRx::new(rx), Value::Nil).into_lua_multi(&lua)
|
||||
} else {
|
||||
(InputRx::new(Debounce::new(rx, Duration::from_secs_f64(debounce))), Value::Nil)
|
||||
.into_lua_multi(&lua)
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
|
||||
// TODO: redesign the confirm API
|
||||
// ya.raw_set(
|
||||
// "confirm",
|
||||
// lua.create_async_function(|_, t: Table| async move {
|
||||
// let result = ConfirmProxy::show(ConfirmCfg {
|
||||
// title: t.raw_get("title")?,
|
||||
// content: t.raw_get("content")?,
|
||||
// position: Position::try_from(t.raw_get::<_, Table>("position")?)?.into(),
|
||||
// });
|
||||
// Ok(result.await)
|
||||
// })?,
|
||||
// )?;
|
||||
|
||||
ya.raw_set(
|
||||
"notify",
|
||||
lua.create_function(|_, t: Table| {
|
||||
AppProxy::notify(t.try_into()?);
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +1,20 @@
|
||||
use mlua::{Lua, MultiValue, Table};
|
||||
use mlua::{Function, Lua, MultiValue};
|
||||
use tracing::{debug, error};
|
||||
|
||||
use super::Utils;
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn log(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"dbg",
|
||||
lua.create_function(|_, values: MultiValue| {
|
||||
let s = values.into_iter().map(|v| format!("{v:#?}")).collect::<Vec<_>>().join(" ");
|
||||
Ok(debug!("{s}"))
|
||||
})?,
|
||||
)?;
|
||||
pub(super) fn dbg(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, values: MultiValue| {
|
||||
let s = values.into_iter().map(|v| format!("{v:#?}")).collect::<Vec<_>>().join(" ");
|
||||
Ok(debug!("{s}"))
|
||||
})
|
||||
}
|
||||
|
||||
ya.raw_set(
|
||||
"err",
|
||||
lua.create_function(|_, values: MultiValue| {
|
||||
let s = values.into_iter().map(|v| format!("{v:#?}")).collect::<Vec<_>>().join(" ");
|
||||
Ok(error!("{s}"))
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
pub(super) fn err(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, values: MultiValue| {
|
||||
let s = values.into_iter().map(|v| format!("{v:#?}")).collect::<Vec<_>>().join(" ");
|
||||
Ok(error!("{s}"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use mlua::{AnyUserData, IntoLuaMulti, Lua, Table, Value};
|
||||
use mlua::{AnyUserData, Function, IntoLuaMulti, Lua, Table, Value};
|
||||
use yazi_config::{PREVIEW, preview::PreviewWrap};
|
||||
use yazi_macro::emit;
|
||||
use yazi_shared::{Layer, errors::PeekError, event::Cmd};
|
||||
@ -34,43 +34,37 @@ impl TryFrom<Table> for PreviewLock {
|
||||
}
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn preview(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"preview_code",
|
||||
lua.create_async_function(|lua, t: Table| async move {
|
||||
let area: Rect = t.raw_get("area")?;
|
||||
let mut lock = PreviewLock::try_from(t)?;
|
||||
pub(super) fn preview_code(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, t: Table| async move {
|
||||
let area: Rect = t.raw_get("area")?;
|
||||
let mut lock = PreviewLock::try_from(t)?;
|
||||
|
||||
let inner = match Highlighter::new(&lock.url).highlight(lock.skip, *area).await {
|
||||
Ok(text) => text,
|
||||
Err(e @ PeekError::Exceed(max)) => return (e.to_string(), max).into_lua_multi(&lua),
|
||||
Err(e @ PeekError::Unexpected(_)) => {
|
||||
return (e.to_string(), Value::Nil).into_lua_multi(&lua);
|
||||
}
|
||||
};
|
||||
let inner = match Highlighter::new(&lock.url).highlight(lock.skip, *area).await {
|
||||
Ok(text) => text,
|
||||
Err(e @ PeekError::Exceed(max)) => return (e.to_string(), max).into_lua_multi(&lua),
|
||||
Err(e @ PeekError::Unexpected(_)) => {
|
||||
return (e.to_string(), Value::Nil).into_lua_multi(&lua);
|
||||
}
|
||||
};
|
||||
|
||||
lock.data = vec![Box::new(Text {
|
||||
area,
|
||||
inner,
|
||||
wrap: if PREVIEW.wrap == PreviewWrap::Yes { WRAP } else { WRAP_NO },
|
||||
})];
|
||||
lock.data = vec![Box::new(Text {
|
||||
area,
|
||||
inner,
|
||||
wrap: if PREVIEW.wrap == PreviewWrap::Yes { WRAP } else { WRAP_NO },
|
||||
})];
|
||||
|
||||
emit!(Call(Cmd::new("update_peeked").with_any("lock", lock), Layer::Manager));
|
||||
(Value::Nil, Value::Nil).into_lua_multi(&lua)
|
||||
})?,
|
||||
)?;
|
||||
emit!(Call(Cmd::new("update_peeked").with_any("lock", lock), Layer::Manager));
|
||||
(Value::Nil, Value::Nil).into_lua_multi(&lua)
|
||||
})
|
||||
}
|
||||
|
||||
ya.raw_set(
|
||||
"preview_widgets",
|
||||
lua.create_async_function(|_, (t, widgets): (Table, Vec<AnyUserData>)| async move {
|
||||
let mut lock = PreviewLock::try_from(t)?;
|
||||
lock.data = widgets.into_iter().filter_map(|ud| cast_to_renderable(&ud)).collect();
|
||||
pub(super) fn preview_widgets(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|_, (t, widgets): (Table, Vec<AnyUserData>)| async move {
|
||||
let mut lock = PreviewLock::try_from(t)?;
|
||||
lock.data = widgets.into_iter().filter_map(|ud| cast_to_renderable(&ud)).collect();
|
||||
|
||||
emit!(Call(Cmd::new("update_peeked").with_any("lock", lock), Layer::Manager));
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
emit!(Call(Cmd::new("update_peeked").with_any("lock", lock), Layer::Manager));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use mlua::{ExternalError, ExternalResult, Function, Lua, MultiValue, Table, Value};
|
||||
use mlua::{ExternalError, ExternalResult, Function, Lua, MultiValue, Value};
|
||||
use tokio::sync::oneshot;
|
||||
use yazi_dds::Sendable;
|
||||
use yazi_proxy::{AppProxy, options::{PluginCallback, PluginOpt}};
|
||||
@ -8,29 +8,8 @@ use super::Utils;
|
||||
use crate::{loader::LOADER, runtime::RtRef};
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn sync(lua: &'static Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"sync",
|
||||
lua.create_function(|lua, f: Function| {
|
||||
let mut rt = lua.named_registry_value::<RtRef>("rt")?;
|
||||
if !rt.put_block(f.clone()) {
|
||||
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
|
||||
}
|
||||
|
||||
let cur = rt.current().unwrap().to_owned();
|
||||
lua.create_function(move |lua, mut args: MultiValue| {
|
||||
args.push_front(Value::Table(LOADER.try_load(lua, &cur)?));
|
||||
f.call::<MultiValue>(args)
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn sync_isolate(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"sync",
|
||||
pub(super) fn sync(lua: &Lua, isolate: bool) -> mlua::Result<Function> {
|
||||
if isolate {
|
||||
lua.create_function(|lua, ()| {
|
||||
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.next_block() else {
|
||||
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
|
||||
@ -43,10 +22,21 @@ impl Utils {
|
||||
Err("block spawned by `ya.sync()` must be called in a plugin").into_lua_err()
|
||||
}
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
})
|
||||
} else {
|
||||
lua.create_function(|lua, f: Function| {
|
||||
let mut rt = lua.named_registry_value::<RtRef>("rt")?;
|
||||
if !rt.put_block(f.clone()) {
|
||||
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
let cur = rt.current().unwrap().to_owned();
|
||||
lua.create_function(move |lua, mut args: MultiValue| {
|
||||
args.push_front(Value::Table(LOADER.try_load(lua, &cur)?));
|
||||
f.call::<MultiValue>(args)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn retrieve(id: &str, calls: usize, args: MultiValue) -> mlua::Result<Vec<Data>> {
|
||||
|
@ -1,12 +1,13 @@
|
||||
use mlua::{Lua, Table};
|
||||
use mlua::{Function, Lua};
|
||||
|
||||
use super::Utils;
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn target(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set("target_os", lua.create_function(|_, ()| Ok(std::env::consts::OS))?)?;
|
||||
ya.raw_set("target_family", lua.create_function(|_, ()| Ok(std::env::consts::FAMILY))?)?;
|
||||
pub(super) fn target_os(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, ()| Ok(std::env::consts::OS))
|
||||
}
|
||||
|
||||
Ok(())
|
||||
pub(super) fn target_family(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, ()| Ok(std::env::consts::FAMILY))
|
||||
}
|
||||
}
|
||||
|
@ -1,85 +1,69 @@
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
use md5::{Digest, Md5};
|
||||
use mlua::{Lua, Table};
|
||||
use mlua::{Function, Lua, Table};
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
use super::Utils;
|
||||
use crate::CLIPBOARD;
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn text(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
// TODO: deprecate this in the future
|
||||
ya.raw_set(
|
||||
"md5",
|
||||
lua.create_async_function(|_, s: mlua::String| async move {
|
||||
Ok(format!("{:x}", Md5::new_with_prefix(s.as_bytes()).finalize()))
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"hash",
|
||||
lua.create_async_function(|_, s: mlua::String| async move {
|
||||
Ok(format!("{:x}", Md5::new_with_prefix(s.as_bytes()).finalize()))
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"quote",
|
||||
lua.create_function(|lua, (s, unix): (mlua::String, Option<bool>)| {
|
||||
let s = s.to_str()?;
|
||||
let s = match unix {
|
||||
Some(true) => yazi_shared::shell::escape_unix(s.as_ref()),
|
||||
Some(false) => yazi_shared::shell::escape_windows(s.as_ref()),
|
||||
None => yazi_shared::shell::escape_native(s.as_ref()),
|
||||
};
|
||||
lua.create_string(s.as_ref())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"truncate",
|
||||
lua.create_function(|_, (text, t): (mlua::String, Table)| {
|
||||
let (max, text) = (t.raw_get("max")?, text.to_string_lossy());
|
||||
|
||||
Ok(if t.raw_get("rtl").unwrap_or(false) {
|
||||
Self::truncate(text.chars().rev(), max).into_iter().rev().collect()
|
||||
} else {
|
||||
Self::truncate(text.chars(), max).into_iter().collect::<String>()
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"clipboard",
|
||||
lua.create_async_function(|lua, text: Option<String>| async move {
|
||||
if let Some(text) = text {
|
||||
CLIPBOARD.set(text).await;
|
||||
Ok(None)
|
||||
} else {
|
||||
Some(lua.create_string(CLIPBOARD.get().await.as_encoded_bytes())).transpose()
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
pub(super) fn hash(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|_, s: mlua::String| async move {
|
||||
Ok(format!("{:x}", Md5::new_with_prefix(s.as_bytes()).finalize()))
|
||||
})
|
||||
}
|
||||
|
||||
fn truncate(mut chars: impl Iterator<Item = char>, max: usize) -> Vec<char> {
|
||||
let mut width = 0;
|
||||
let flow = chars.try_fold(Vec::with_capacity(max), |mut v, c| {
|
||||
width += c.width().unwrap_or(0);
|
||||
if width < max {
|
||||
v.push(c);
|
||||
ControlFlow::Continue(v)
|
||||
} else {
|
||||
ControlFlow::Break(v)
|
||||
}
|
||||
});
|
||||
pub(super) fn quote(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, (s, unix): (mlua::String, Option<bool>)| {
|
||||
let s = s.to_str()?;
|
||||
let s = match unix {
|
||||
Some(true) => yazi_shared::shell::escape_unix(s.as_ref()),
|
||||
Some(false) => yazi_shared::shell::escape_windows(s.as_ref()),
|
||||
None => yazi_shared::shell::escape_native(s.as_ref()),
|
||||
};
|
||||
lua.create_string(s.as_ref())
|
||||
})
|
||||
}
|
||||
|
||||
match flow {
|
||||
ControlFlow::Break(v) => v,
|
||||
ControlFlow::Continue(v) => v,
|
||||
pub(super) fn truncate(lua: &Lua) -> mlua::Result<Function> {
|
||||
fn truncate_impl(mut chars: impl Iterator<Item = char>, max: usize) -> Vec<char> {
|
||||
let mut width = 0;
|
||||
let flow = chars.try_fold(Vec::with_capacity(max), |mut v, c| {
|
||||
width += c.width().unwrap_or(0);
|
||||
if width < max {
|
||||
v.push(c);
|
||||
ControlFlow::Continue(v)
|
||||
} else {
|
||||
ControlFlow::Break(v)
|
||||
}
|
||||
});
|
||||
|
||||
match flow {
|
||||
ControlFlow::Break(v) => v,
|
||||
ControlFlow::Continue(v) => v,
|
||||
}
|
||||
}
|
||||
|
||||
lua.create_function(|_, (text, t): (mlua::String, Table)| {
|
||||
let (max, text) = (t.raw_get("max")?, text.to_string_lossy());
|
||||
|
||||
Ok(if t.raw_get("rtl").unwrap_or(false) {
|
||||
truncate_impl(text.chars().rev(), max).into_iter().rev().collect()
|
||||
} else {
|
||||
truncate_impl(text.chars(), max).into_iter().collect::<String>()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn clipboard(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, text: Option<String>| async move {
|
||||
if let Some(text) = text {
|
||||
CLIPBOARD.set(text).await;
|
||||
Ok(None)
|
||||
} else {
|
||||
Some(lua.create_string(CLIPBOARD.get().await.as_encoded_bytes())).transpose()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,24 @@
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use mlua::{ExternalError, Lua, Table};
|
||||
use mlua::{ExternalError, Function, Lua};
|
||||
|
||||
use super::Utils;
|
||||
|
||||
impl Utils {
|
||||
pub(super) fn time(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
ya.raw_set(
|
||||
"time",
|
||||
lua.create_function(|_, ()| {
|
||||
Ok(SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())
|
||||
})?,
|
||||
)?;
|
||||
pub(super) fn time(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, ()| {
|
||||
Ok(SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_secs_f64()).ok())
|
||||
})
|
||||
}
|
||||
|
||||
ya.raw_set(
|
||||
"sleep",
|
||||
lua.create_async_function(|_, secs: f64| async move {
|
||||
if secs < 0.0 {
|
||||
return Err("negative sleep duration".into_lua_err());
|
||||
}
|
||||
pub(super) fn sleep(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|_, secs: f64| async move {
|
||||
if secs < 0.0 {
|
||||
return Err("negative sleep duration".into_lua_err());
|
||||
}
|
||||
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs_f64(secs)).await;
|
||||
Ok(())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs_f64(secs)).await;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +1,57 @@
|
||||
use mlua::{Lua, Table};
|
||||
use mlua::{Function, Lua};
|
||||
|
||||
use super::Utils;
|
||||
|
||||
#[cfg(unix)]
|
||||
static HOSTNAME_CACHE: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
|
||||
|
||||
impl Utils {
|
||||
#[cfg(unix)]
|
||||
pub(super) fn user(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||
use uzers::{Groups, Users};
|
||||
use yazi_shared::{USERS_CACHE, hostname};
|
||||
|
||||
use crate::utils::HOSTNAME_CACHE;
|
||||
|
||||
ya.raw_set("uid", lua.create_function(|_, ()| Ok(USERS_CACHE.get_current_uid()))?)?;
|
||||
|
||||
ya.raw_set("gid", lua.create_function(|_, ()| Ok(USERS_CACHE.get_current_gid()))?)?;
|
||||
|
||||
ya.raw_set(
|
||||
"user_name",
|
||||
lua.create_function(|lua, uid: Option<u32>| {
|
||||
USERS_CACHE
|
||||
.get_user_by_uid(uid.unwrap_or_else(|| USERS_CACHE.get_current_uid()))
|
||||
.map(|s| lua.create_string(s.name().as_encoded_bytes()))
|
||||
.transpose()
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"group_name",
|
||||
lua.create_function(|lua, gid: Option<u32>| {
|
||||
USERS_CACHE
|
||||
.get_group_by_gid(gid.unwrap_or_else(|| USERS_CACHE.get_current_gid()))
|
||||
.map(|s| lua.create_string(s.name().as_encoded_bytes()))
|
||||
.transpose()
|
||||
})?,
|
||||
)?;
|
||||
|
||||
ya.raw_set(
|
||||
"host_name",
|
||||
lua.create_function(|lua, ()| {
|
||||
HOSTNAME_CACHE
|
||||
.get_or_init(|| hostname().ok())
|
||||
.as_ref()
|
||||
.map(|s| lua.create_string(s))
|
||||
.transpose()
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
pub(super) fn uid(lua: &Lua) -> mlua::Result<Function> {
|
||||
use uzers::Users;
|
||||
lua.create_function(|_, ()| Ok(yazi_shared::USERS_CACHE.get_current_uid()))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(super) fn user(_lua: &Lua, _ya: &Table) -> mlua::Result<()> { Ok(()) }
|
||||
#[cfg(unix)]
|
||||
pub(super) fn gid(lua: &Lua) -> mlua::Result<Function> {
|
||||
use uzers::Groups;
|
||||
lua.create_function(|_, ()| Ok(yazi_shared::USERS_CACHE.get_current_gid()))
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(super) fn user_name(lua: &Lua) -> mlua::Result<Function> {
|
||||
use uzers::Users;
|
||||
use yazi_shared::USERS_CACHE;
|
||||
|
||||
lua.create_function(|lua, uid: Option<u32>| {
|
||||
USERS_CACHE
|
||||
.get_user_by_uid(uid.unwrap_or_else(|| USERS_CACHE.get_current_uid()))
|
||||
.map(|s| lua.create_string(s.name().as_encoded_bytes()))
|
||||
.transpose()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(super) fn group_name(lua: &Lua) -> mlua::Result<Function> {
|
||||
use uzers::Groups;
|
||||
use yazi_shared::USERS_CACHE;
|
||||
|
||||
lua.create_function(|lua, gid: Option<u32>| {
|
||||
USERS_CACHE
|
||||
.get_group_by_gid(gid.unwrap_or_else(|| USERS_CACHE.get_current_gid()))
|
||||
.map(|s| lua.create_string(s.name().as_encoded_bytes()))
|
||||
.transpose()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(super) fn host_name(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, ()| {
|
||||
HOSTNAME_CACHE
|
||||
.get_or_init(|| yazi_shared::hostname().ok())
|
||||
.as_ref()
|
||||
.map(|s| lua.create_string(s))
|
||||
.transpose()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,44 +1,80 @@
|
||||
use mlua::Lua;
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(super) static HOSTNAME_CACHE: std::sync::OnceLock<Option<String>> = std::sync::OnceLock::new();
|
||||
use mlua::{IntoLua, Lua, Table, Value};
|
||||
|
||||
pub(super) struct Utils;
|
||||
|
||||
pub fn install(lua: &'static Lua) -> mlua::Result<()> {
|
||||
let ya = lua.create_table()?;
|
||||
pub fn compose(lua: &Lua, isolate: bool) -> mlua::Result<Table> {
|
||||
let index = lua.create_function(move |lua, (ts, key): (Table, mlua::String)| {
|
||||
let value = match key.as_bytes().as_ref() {
|
||||
// App
|
||||
b"hide" => Utils::hide(lua)?,
|
||||
|
||||
Utils::app(lua, &ya)?;
|
||||
Utils::cache(lua, &ya)?;
|
||||
Utils::call(lua, &ya)?;
|
||||
Utils::image(lua, &ya)?;
|
||||
Utils::layer(lua, &ya)?;
|
||||
Utils::log(lua, &ya)?;
|
||||
Utils::preview(lua, &ya)?;
|
||||
Utils::sync(lua, &ya)?;
|
||||
Utils::target(lua, &ya)?;
|
||||
Utils::text(lua, &ya)?;
|
||||
Utils::time(lua, &ya)?;
|
||||
Utils::user(lua, &ya)?;
|
||||
// Cache
|
||||
b"file_cache" => Utils::file_cache(lua)?,
|
||||
|
||||
lua.globals().raw_set("ya", ya)
|
||||
}
|
||||
|
||||
pub fn install_isolate(lua: &Lua) -> mlua::Result<()> {
|
||||
let ya = lua.create_table()?;
|
||||
|
||||
Utils::app(lua, &ya)?;
|
||||
Utils::cache(lua, &ya)?;
|
||||
Utils::call(lua, &ya)?;
|
||||
Utils::image(lua, &ya)?;
|
||||
Utils::layer(lua, &ya)?;
|
||||
Utils::log(lua, &ya)?;
|
||||
Utils::preview(lua, &ya)?;
|
||||
Utils::sync_isolate(lua, &ya)?;
|
||||
Utils::target(lua, &ya)?;
|
||||
Utils::text(lua, &ya)?;
|
||||
Utils::time(lua, &ya)?;
|
||||
Utils::user(lua, &ya)?;
|
||||
|
||||
lua.globals().raw_set("ya", ya)
|
||||
// Call
|
||||
b"render" => Utils::render(lua)?,
|
||||
b"redraw_with" => Utils::redraw_with(lua)?,
|
||||
b"app_emit" => Utils::app_emit(lua)?,
|
||||
b"manager_emit" => Utils::manager_emit(lua)?,
|
||||
b"input_emit" => Utils::input_emit(lua)?,
|
||||
|
||||
// Image
|
||||
b"image_show" => Utils::image_show(lua)?,
|
||||
b"image_precache" => Utils::image_precache(lua)?,
|
||||
|
||||
// Layout
|
||||
b"which" => Utils::which(lua)?,
|
||||
b"input" => Utils::input(lua)?,
|
||||
b"notify" => Utils::notify(lua)?,
|
||||
|
||||
// Log
|
||||
b"dbg" => Utils::dbg(lua)?,
|
||||
b"err" => Utils::err(lua)?,
|
||||
|
||||
// Preview
|
||||
b"preview_code" => Utils::preview_code(lua)?,
|
||||
b"preview_widgets" => Utils::preview_widgets(lua)?,
|
||||
|
||||
// Sync
|
||||
b"sync" => Utils::sync(lua, isolate)?,
|
||||
|
||||
// Target
|
||||
b"target_os" => Utils::target_os(lua)?,
|
||||
b"target_family" => Utils::target_family(lua)?,
|
||||
|
||||
// Text
|
||||
b"md5" => Utils::hash(lua)?, // TODO: deprecate this in the future
|
||||
b"hash" => Utils::hash(lua)?,
|
||||
b"quote" => Utils::quote(lua)?,
|
||||
b"truncate" => Utils::truncate(lua)?,
|
||||
b"clipboard" => Utils::clipboard(lua)?,
|
||||
|
||||
// Time
|
||||
b"time" => Utils::time(lua)?,
|
||||
b"sleep" => Utils::sleep(lua)?,
|
||||
|
||||
// User
|
||||
#[cfg(unix)]
|
||||
b"uid" => Utils::uid(lua)?,
|
||||
#[cfg(unix)]
|
||||
b"gid" => Utils::gid(lua)?,
|
||||
#[cfg(unix)]
|
||||
b"user_name" => Utils::user_name(lua)?,
|
||||
#[cfg(unix)]
|
||||
b"group_name" => Utils::group_name(lua)?,
|
||||
#[cfg(unix)]
|
||||
b"host_name" => Utils::host_name(lua)?,
|
||||
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)?;
|
||||
|
||||
ts.raw_set(key, value.clone())?;
|
||||
Ok(value)
|
||||
})?;
|
||||
|
||||
let ya = lua.create_table_with_capacity(0, 40)?;
|
||||
ya.set_metatable(Some(lua.create_table_from([("__index", index)])?));
|
||||
|
||||
Ok(ya)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user