mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
feat: new fs.access() API to access the filesystem (#3668)
This commit is contained in:
parent
0aeeb3b0f7
commit
1a121bbfb0
8 changed files with 174 additions and 108 deletions
|
|
@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
|
||||
### Added
|
||||
|
||||
- New `fs.access()` API to access the filesystem ([#3668])
|
||||
- Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638])
|
||||
- New `relay-notify-push` DDS event to allow custom notification handlers ([#3642])
|
||||
- Custom tab name ([#3666])
|
||||
|
|
@ -1645,3 +1646,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|||
[#3648]: https://github.com/sxyazi/yazi/pull/3648
|
||||
[#3661]: https://github.com/sxyazi/yazi/pull/3661
|
||||
[#3666]: https://github.com/sxyazi/yazi/pull/3666
|
||||
[#3668]: https://github.com/sxyazi/yazi/pull/3668
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<br>
|
||||
<img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-02.png">
|
||||
<br>
|
||||
<h>Warp, built for coding with multiple AI agents</b>
|
||||
<b>Warp, built for coding with multiple AI agents</b>
|
||||
<br>
|
||||
<sup>Available for macOS, Linux and Windows</sup>
|
||||
</a>
|
||||
|
|
|
|||
42
yazi-binding/src/access.rs
Normal file
42
yazi-binding/src/access.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use mlua::{AnyUserData, IntoLuaMulti, UserData, UserDataMethods, Value};
|
||||
use yazi_fs::provider::FileBuilder;
|
||||
|
||||
use crate::{Error, Fd, UrlRef};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Access(yazi_vfs::provider::Gate);
|
||||
|
||||
impl UserData for Access {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_function_mut("append", |_, (ud, append): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.append(append);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function_mut("create", |_, (ud, create): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.create(create);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function_mut("create_new", |_, (ud, create_new): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.create_new(create_new);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_async_method("open", |lua, me, url: UrlRef| async move {
|
||||
match me.0.open(&*url).await {
|
||||
Ok(fd) => Fd(fd).into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
});
|
||||
methods.add_function_mut("read", |_, (ud, read): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.read(read);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function_mut("truncate", |_, (ud, truncate): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.truncate(truncate);
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function_mut("write", |_, (ud, write): (AnyUserData, bool)| {
|
||||
ud.borrow_mut::<Self>()?.0.write(write);
|
||||
Ok(ud)
|
||||
});
|
||||
}
|
||||
}
|
||||
23
yazi-binding/src/fd.rs
Normal file
23
yazi-binding/src/fd.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use mlua::{IntoLuaMulti, UserData, UserDataMethods};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub struct Fd(pub yazi_vfs::provider::RwFile);
|
||||
|
||||
impl UserData for Fd {
|
||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||
methods.add_async_method_mut("write_all", |lua, mut me, src: mlua::String| async move {
|
||||
match me.0.write_all(&*src.as_bytes()).await {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
});
|
||||
methods.add_async_method_mut("flush", |lua, mut me, ()| async move {
|
||||
match me.0.flush().await {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -2,4 +2,4 @@ mod macros;
|
|||
|
||||
yazi_macro::mod_pub!(elements);
|
||||
|
||||
yazi_macro::mod_flat!(calculator cha chan chord_cow color composer error file handle icon id image input iter layer mouse path permit range runtime scheme stage style url utils);
|
||||
yazi_macro::mod_flat!(access calculator cha chan chord_cow color composer error fd file handle icon id image input iter layer mouse path permit range runtime scheme stage style url utils);
|
||||
|
|
|
|||
|
|
@ -50,28 +50,21 @@ function Header:flags()
|
|||
end
|
||||
|
||||
function Header:count()
|
||||
local yanked = #cx.yanked
|
||||
local selected = #self._tab.selected
|
||||
local yanked = selected > 0 and 0 or #cx.yanked
|
||||
|
||||
local count, style
|
||||
if yanked == 0 then
|
||||
count = #self._tab.selected
|
||||
style = th.mgr.count_selected
|
||||
elseif cx.yanked.is_cut then
|
||||
count = yanked
|
||||
style = th.mgr.count_cut
|
||||
else
|
||||
count = yanked
|
||||
style = th.mgr.count_copied
|
||||
end
|
||||
|
||||
if count == 0 then
|
||||
local span
|
||||
if selected > 0 then
|
||||
span = ui.Span(" " .. selected .. " "):style(th.mgr.count_selected)
|
||||
elseif yanked <= 0 then
|
||||
return ""
|
||||
elseif cx.yanked.is_cut then
|
||||
span = ui.Span(" " .. yanked .. " "):style(th.mgr.count_cut)
|
||||
else
|
||||
span = ui.Span(" " .. yanked .. " "):style(th.mgr.count_copied)
|
||||
end
|
||||
|
||||
return ui.Line {
|
||||
ui.Span(string.format(" %d ", count)):style(style),
|
||||
" ",
|
||||
}
|
||||
return ui.Line { span, " " }
|
||||
end
|
||||
|
||||
function Header:reflow() return { self } end
|
||||
|
|
|
|||
|
|
@ -10,19 +10,20 @@ use yazi_vfs::{VfsFile, provider};
|
|||
pub fn compose() -> Composer<ComposerGet, ComposerSet> {
|
||||
fn get(lua: &Lua, key: &[u8]) -> mlua::Result<Value> {
|
||||
match key {
|
||||
b"op" => op(lua)?,
|
||||
b"cwd" => cwd(lua)?,
|
||||
b"access" => access(lua)?,
|
||||
b"calc_size" => calc_size(lua)?,
|
||||
b"cha" => cha(lua)?,
|
||||
b"copy" => copy(lua)?,
|
||||
b"write" => write(lua)?,
|
||||
b"create" => create(lua)?,
|
||||
b"cwd" => cwd(lua)?,
|
||||
b"expand_url" => expand_url(lua)?,
|
||||
b"op" => op(lua)?,
|
||||
b"partitions" => partitions(lua)?,
|
||||
b"read_dir" => read_dir(lua)?,
|
||||
b"remove" => remove(lua)?,
|
||||
b"rename" => rename(lua)?,
|
||||
b"read_dir" => read_dir(lua)?,
|
||||
b"calc_size" => calc_size(lua)?,
|
||||
b"expand_url" => expand_url(lua)?,
|
||||
b"unique_name" => unique_name(lua)?,
|
||||
b"partitions" => partitions(lua)?,
|
||||
b"write" => write(lua)?,
|
||||
_ => return Ok(Value::Nil),
|
||||
}
|
||||
.into_lua(lua)
|
||||
|
|
@ -33,19 +34,22 @@ pub fn compose() -> Composer<ComposerGet, ComposerSet> {
|
|||
Composer::new(get, set)
|
||||
}
|
||||
|
||||
fn op(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, (name, t): (mlua::String, Table)| match &*name.as_bytes() {
|
||||
b"part" => super::FilesOp::part(lua, t),
|
||||
b"done" => super::FilesOp::done(lua, t),
|
||||
b"size" => super::FilesOp::size(lua, t),
|
||||
_ => Err("Unknown operation".into_lua_err())?,
|
||||
})
|
||||
fn access(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, ()| Ok(yazi_binding::Access::default()))
|
||||
}
|
||||
|
||||
fn cwd(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, ()| match std::env::current_dir() {
|
||||
Ok(p) => Url::new(p).into_lua_multi(lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(lua),
|
||||
fn calc_size(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, url: UrlRef| async move {
|
||||
let it = if let Some(path) = url.as_local() {
|
||||
yazi_fs::provider::local::SizeCalculator::new(path).await.map(SizeCalculator::Local)
|
||||
} else {
|
||||
yazi_vfs::provider::SizeCalculator::new(&*url).await.map(SizeCalculator::Remote)
|
||||
};
|
||||
|
||||
match it {
|
||||
Ok(it) => it.into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -73,15 +77,6 @@ fn copy(lua: &Lua) -> mlua::Result<Function> {
|
|||
})
|
||||
}
|
||||
|
||||
fn write(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (url, data): (UrlRef, mlua::String)| async move {
|
||||
match provider::write(&*url, data.as_bytes()).await {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn create(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (r#type, url): (mlua::String, UrlRef)| async move {
|
||||
let result = match &*r#type.as_bytes() {
|
||||
|
|
@ -97,29 +92,59 @@ fn create(lua: &Lua) -> mlua::Result<Function> {
|
|||
})
|
||||
}
|
||||
|
||||
fn remove(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (r#type, url): (mlua::String, UrlRef)| async move {
|
||||
let result = match &*r#type.as_bytes() {
|
||||
b"file" => provider::remove_file(&*url).await,
|
||||
b"dir" => provider::remove_dir(&*url).await,
|
||||
b"dir_all" => provider::remove_dir_all(&*url).await,
|
||||
b"dir_clean" => provider::remove_dir_clean(&*url).await,
|
||||
_ => Err("Removal type must be 'file', 'dir', 'dir_all', or 'dir_clean'".into_lua_err())?,
|
||||
};
|
||||
fn cwd(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, ()| match std::env::current_dir() {
|
||||
Ok(p) => Url::new(p).into_lua_multi(lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(lua),
|
||||
})
|
||||
}
|
||||
|
||||
match result {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
fn expand_url(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, value: Value| {
|
||||
use yazi_fs::path::expand_url;
|
||||
match &value {
|
||||
Value::String(s) => Url::new(expand_url(UrlCow::try_from(&*s.as_bytes())?)).into_lua(lua),
|
||||
Value::UserData(ud) => {
|
||||
if let u = expand_url(&*ud.borrow::<yazi_binding::Url>()?)
|
||||
&& u.is_owned()
|
||||
{
|
||||
Url::new(u.into_owned()).into_lua(lua)
|
||||
} else {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
_ => Err("must be a string or a Url".into_lua_err())?,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn rename(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (from, to): (UrlRef, UrlRef)| async move {
|
||||
match provider::rename(&*from, &*to).await {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
fn op(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, (name, t): (mlua::String, Table)| match &*name.as_bytes() {
|
||||
b"part" => super::FilesOp::part(lua, t),
|
||||
b"done" => super::FilesOp::done(lua, t),
|
||||
b"size" => super::FilesOp::size(lua, t),
|
||||
_ => Err("Unknown operation".into_lua_err())?,
|
||||
})
|
||||
}
|
||||
|
||||
fn partitions(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, ()| async move {
|
||||
PARTITIONS
|
||||
.read()
|
||||
.iter()
|
||||
.filter(|&p| !p.systemic())
|
||||
.map(|p| {
|
||||
lua.create_table_from([
|
||||
("src", p.src.clone().into_lua(&lua)?),
|
||||
("dist", p.dist.clone().into_lua(&lua)?),
|
||||
("label", p.label.clone().into_lua(&lua)?),
|
||||
("fstype", p.fstype.clone().into_lua(&lua)?),
|
||||
("external", p.external.into_lua(&lua)?),
|
||||
("removable", p.removable.into_lua(&lua)?),
|
||||
])
|
||||
})
|
||||
.collect::<mlua::Result<Vec<Table>>>()
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -164,37 +189,28 @@ fn read_dir(lua: &Lua) -> mlua::Result<Function> {
|
|||
})
|
||||
}
|
||||
|
||||
fn calc_size(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, url: UrlRef| async move {
|
||||
let it = if let Some(path) = url.as_local() {
|
||||
yazi_fs::provider::local::SizeCalculator::new(path).await.map(SizeCalculator::Local)
|
||||
} else {
|
||||
yazi_vfs::provider::SizeCalculator::new(&*url).await.map(SizeCalculator::Remote)
|
||||
fn remove(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (r#type, url): (mlua::String, UrlRef)| async move {
|
||||
let result = match &*r#type.as_bytes() {
|
||||
b"file" => provider::remove_file(&*url).await,
|
||||
b"dir" => provider::remove_dir(&*url).await,
|
||||
b"dir_all" => provider::remove_dir_all(&*url).await,
|
||||
b"dir_clean" => provider::remove_dir_clean(&*url).await,
|
||||
_ => Err("Removal type must be 'file', 'dir', 'dir_all', or 'dir_clean'".into_lua_err())?,
|
||||
};
|
||||
|
||||
match it {
|
||||
Ok(it) => it.into_lua_multi(&lua),
|
||||
Err(e) => (Value::Nil, Error::Io(e)).into_lua_multi(&lua),
|
||||
match result {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
fn expand_url(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|lua, value: Value| {
|
||||
use yazi_fs::path::expand_url;
|
||||
match &value {
|
||||
Value::String(s) => Url::new(expand_url(UrlCow::try_from(&*s.as_bytes())?)).into_lua(lua),
|
||||
Value::UserData(ud) => {
|
||||
if let u = expand_url(&*ud.borrow::<yazi_binding::Url>()?)
|
||||
&& u.is_owned()
|
||||
{
|
||||
Url::new(u.into_owned()).into_lua(lua)
|
||||
} else {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
_ => Err("must be a string or a Url".into_lua_err())?,
|
||||
fn rename(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (from, to): (UrlRef, UrlRef)| async move {
|
||||
match provider::rename(&*from, &*to).await {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -208,22 +224,11 @@ fn unique_name(lua: &Lua) -> mlua::Result<Function> {
|
|||
})
|
||||
}
|
||||
|
||||
fn partitions(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, ()| async move {
|
||||
PARTITIONS
|
||||
.read()
|
||||
.iter()
|
||||
.filter(|&p| !p.systemic())
|
||||
.map(|p| {
|
||||
lua.create_table_from([
|
||||
("src", p.src.clone().into_lua(&lua)?),
|
||||
("dist", p.dist.clone().into_lua(&lua)?),
|
||||
("label", p.label.clone().into_lua(&lua)?),
|
||||
("fstype", p.fstype.clone().into_lua(&lua)?),
|
||||
("external", p.external.into_lua(&lua)?),
|
||||
("removable", p.removable.into_lua(&lua)?),
|
||||
])
|
||||
})
|
||||
.collect::<mlua::Result<Vec<Table>>>()
|
||||
fn write(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_async_function(|lua, (url, data): (UrlRef, mlua::String)| async move {
|
||||
match provider::write(&*url, data.as_bytes()).await {
|
||||
Ok(()) => true.into_lua_multi(&lua),
|
||||
Err(e) => (false, Error::Io(e)).into_lua_multi(&lua),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::any::TypeId;
|
|||
|
||||
use mlua::{AnyUserData, ExternalError, Function, Lua};
|
||||
use tokio::process::{ChildStderr, ChildStdin, ChildStdout};
|
||||
use yazi_binding::Id;
|
||||
use yazi_binding::{Fd, Id};
|
||||
|
||||
use super::Utils;
|
||||
|
||||
|
|
@ -20,6 +20,7 @@ impl Utils {
|
|||
pub(super) fn drop(lua: &Lua) -> mlua::Result<Function> {
|
||||
lua.create_function(|_, ud: AnyUserData| {
|
||||
match ud.type_id() {
|
||||
Some(t) if t == TypeId::of::<Fd>() => {}
|
||||
Some(t) if t == TypeId::of::<ChildStdin>() => {}
|
||||
Some(t) if t == TypeId::of::<ChildStdout>() => {}
|
||||
Some(t) if t == TypeId::of::<ChildStderr>() => {}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue