This commit is contained in:
sxyazi 2023-09-27 08:39:55 +08:00
parent 528e4a6130
commit fa2a9cea2c
No known key found for this signature in database
10 changed files with 209 additions and 102 deletions

View file

@ -1 +1 @@
{"flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata"],"language":"en","version":"0.2"} {"language":"en","flagWords":[],"words":["Punct","KEYMAP","splitn","crossterm","YAZI","unar","peekable","ratatui","syntect","pbpaste","pbcopy","ffmpegthumbnailer","oneshot","Posix","Lsar","XADDOS","zoxide","cands","Deque","precache","imageops","IFBLK","IFCHR","IFDIR","IFIFO","IFLNK","IFMT","IFSOCK","IRGRP","IROTH","IRUSR","ISGID","ISUID","ISVTX","IWGRP","IWOTH","IWUSR","IXGRP","IXOTH","IXUSR","libc","winsize","TIOCGWINSZ","xpixel","ypixel","ioerr","appender","Catppuccin","macchiato","gitmodules","Dotfiles","bashprofile","vimrc","flac","webp","exiftool","mediainfo","ripgrep","nvim","indexmap","indexmap","unwatch","canonicalize","serde","fsevent","Ueberzug","iterm","wezterm","sixel","chafa","ueberzugpp"," Überzug"," Überzug","Konsole","Alacritty","Überzug","pkgs","paru","unarchiver","pdftoppm","poppler","prebuild","singlefile","jpegopt","EXIF","rustfmt","mktemp","nanos","xclip","xsel","natord","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","mlua","nonstatic","userdata","metatable"],"version":"0.2"}

View file

@ -13,39 +13,44 @@ function Status.mode()
end end
function Status.size() function Status.size()
local hovered = cx.manager.current_hovered -- cx.manager.current.files
if hovered == nil then
return ui.Span("") -- yazi.print(#cx.manager.current.files)
for key, value in pairs(cx.manager.current.files) do
yazi.print(key, value)
break
end end
return ui.Line( return ui.Span("fff")
ui.Span(" " .. hovered.length .. " "):fg(THEME.status.mode_normal.bg):bg(THEME.status.fancy.bg), -- return ui.Line(
ui.Span(THEME.status.separator.closing):fg(THEME.status.fancy.bg) -- ui.Span(" " .. utils.readable_size(h.length) .. " "):fg(THEME.status.mode_normal.bg):bg(THEME.status.fancy.bg),
) -- ui.Span(THEME.status.separator.closing):fg(THEME.status.fancy.bg)
-- )
end end
function Status.name() function Status.name()
local hovered = cx.manager.current_hovered local h = cx.manager.current.hovered
if hovered == nil then if h == nil then
return ui.Span("") return ui.Span("")
end end
return ui.Span(" " .. utils.basename(hovered.url)) return ui.Span(" " .. utils.basename(h.url))
end end
function Status.permissions() function Status.permissions()
local hovered = cx.manager.current_hovered local h = cx.manager.current.hovered
if hovered == nil then if h == nil then
return ui.Span("") return ui.Span("")
end end
if hovered.permissions == nil then if h.permissions == nil then
return ui.Span("") return ui.Span("")
end end
local spans = {} local spans = {}
for i = 1, #hovered.permissions do for i = 1, #h.permissions do
local c = hovered.permissions:sub(i, i) local c = h.permissions:sub(i, i)
local style = THEME.status.permissions_t local style = THEME.status.permissions_t
if c == "r" then if c == "r" then
style = THEME.status.permissions_r style = THEME.status.permissions_r
@ -61,8 +66,8 @@ end
function Status.percentage() function Status.percentage()
local percent = 0 local percent = 0
local cursor = cx.manager.current_cursor local cursor = cx.manager.current.cursor
local length = cx.manager.current_length local length = cx.manager.current.len()
if cursor ~= 0 and length ~= 0 then if cursor ~= 0 and length ~= 0 then
percent = math.floor((cursor + 1) * 100 / length) percent = math.floor((cursor + 1) * 100 / length)
end end
@ -74,15 +79,19 @@ function Status.percentage()
end end
return ui.Line( return ui.Line(
ui.Span(THEME.status.separator.opening):fg(THEME.status.fancy.bg), ui.Span(" " .. THEME.status.separator.opening):fg(THEME.status.fancy.bg),
ui.Span(percent):fg(THEME.status.mode_normal.bg):bg(THEME.status.fancy.bg) ui.Span(percent):fg(THEME.status.mode_normal.bg):bg(THEME.status.fancy.bg)
) )
end end
function Status.position() function Status.position()
local cursor = cx.manager.current_cursor local cursor = cx.manager.current.cursor
local length = cx.manager.current_length local length = cx.manager.current.length
return ui.Span(string.format(" %d/%d ", cursor + 1, length))
return ui.Line(
ui.Span(string.format(" %2d/%-2d ", cursor + 1, length)):style(THEME.status.mode_normal),
ui.Span(THEME.status.separator.closing):fg(THEME.status.mode_normal.bg)
)
end end
function Status:render(area) function Status:render(area)
@ -91,10 +100,12 @@ function Status:render(area)
:constraints({ ui.Constraint.Percentage(50), ui.Constraint.Percentage(50) }) :constraints({ ui.Constraint.Percentage(50), ui.Constraint.Percentage(50) })
:split(area) :split(area)
local left = ui.Line(self.mode(), self.size(), self.name()) -- local left = ui.Line(self.mode(), self.size(), self.name())
local right = ui.Line(self.permissions(), self.percentage(), self.position()) -- local right = ui.Line(self.permissions(), self.percentage(), self.position())
local left = ui.Line(self.mode(), self.size())
return ui.Paragraph.render( return ui.Paragraph.render(
ui.Paragraph(left):area(chunks[1]), ui.Paragraph(left):area(chunks[1])
ui.Paragraph(right):align(ui.Alignment.RIGHT):area(chunks[2]) -- ui.Paragraph(right):align(ui.Alignment.RIGHT):area(chunks[2])
) )
end end

View file

@ -1,3 +1,13 @@
utils = utils or {} utils = utils or {}
function utils.basename(str) return string.gsub(str, "(.*[/\\])(.*)", "%2") end function utils.basename(str) return string.gsub(str, "(.*[/\\])(.*)", "%2") end
function utils.readable_size(size)
local units = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }
local i = 1
while size > 1024.0 and i < #units do
size = size / 1024.0
i = i + 1
end
return string.format("%.1f %s", size, units[i])
end

View file

@ -1,60 +0,0 @@
use mlua::{LuaSerdeExt, UserData};
// Manager
pub struct Manager<'a>(&'a core::manager::Manager);
impl<'a> Manager<'a> {
pub fn new(manager: &'a core::manager::Manager) -> Self { Self(manager) }
}
impl<'a> UserData for Manager<'a> {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("mode", |_, me| Ok(me.0.active().mode().to_string()));
fields.add_field_method_get("current_cursor", |_, me| Ok(me.0.current().cursor()));
fields.add_field_method_get("current_length", |_, me| Ok(me.0.current().files.len()));
fields.add_field_method_get("current_hovered", |_, me| {
Ok(me.0.current().hovered.as_ref().map(File::from))
});
}
}
// Tasks
pub struct Tasks<'a>(&'a core::tasks::Tasks);
impl<'a> Tasks<'a> {
pub fn new(tasks: &'a core::tasks::Tasks) -> Self { Self(tasks) }
}
impl<'a> UserData for Tasks<'a> {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("progress", |lua, me| lua.to_value(&me.0.progress))
}
}
// File
pub struct File(core::files::File);
impl From<&core::files::File> for File {
fn from(value: &core::files::File) -> Self { Self(value.clone()) }
}
impl UserData for File {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("url", |_, me| Ok(me.0.url().to_string_lossy().to_string()));
fields.add_field_method_get("length", |_, me| Ok(me.0.length()));
fields.add_field_method_get("link_to", |_, me| {
Ok(me.0.link_to().map(|l| l.to_string_lossy().to_string()))
});
fields.add_field_method_get("is_link", |_, me| Ok(me.0.is_link()));
fields.add_field_method_get("is_hidden", |_, me| Ok(me.0.is_hidden()));
// Meta
fields.add_field_method_get("permissions", |_, me| {
Ok(shared::permissions(me.0.meta().permissions()))
});
}
}

View file

@ -0,0 +1,122 @@
use mlua::{AnyUserData, IntoLua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
use tracing::info;
use crate::{Url, LUA};
// Manager
pub struct Manager;
impl Manager {
pub fn make<'a>(
scope: &mlua::Scope<'a, 'a>,
inner: &'a core::manager::Manager,
) -> mlua::Result<AnyUserData<'a>> {
LUA.register_userdata_type::<core::manager::Manager>(|reg| {
reg.add_field_method_get("mode", |_, me| Ok(me.active().mode().to_string()));
reg.add_field_function_get("current", |_, me| me.named_user_value::<AnyUserData>("current"));
reg.add_field_function_get("parent", |_, me| me.named_user_value::<AnyUserData>("parent"));
})?;
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("current", Folder::make(scope, inner.current())?)?;
ud.set_named_user_value("parent", inner.parent().and_then(|p| Folder::make(scope, p).ok()))?;
Ok(ud)
}
}
// Folder
pub struct Folder;
impl Folder {
fn make<'a>(
scope: &mlua::Scope<'a, 'a>,
inner: &'a core::manager::Folder,
) -> mlua::Result<AnyUserData<'a>> {
LUA.register_userdata_type::<core::manager::Folder>(|reg| {
reg.add_field_method_get("cwd", |_, me| Ok(Url::from(&me.cwd)));
reg.add_field_method_get("offset", |_, me| Ok(me.offset()));
reg.add_field_method_get("cursor", |_, me| Ok(me.cursor()));
reg.add_field_function_get("files", |_, me| me.named_user_value::<AnyUserData>("files"));
reg.add_field_function_get("hovered", |_, me| me.named_user_value::<AnyUserData>("hovered"));
// reg.add_field_method_get("window", |_, me| {
// LUA.scope(|scope| scope.create_nonstatic_userdata(Files { files:
// &me.0.files }))
// });
})?;
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("files", Files::make(scope, &inner.files)?)?;
ud.set_named_user_value(
"hovered",
inner.hovered.as_ref().and_then(|h| File::make(scope, h).ok()),
)?;
Ok(ud)
}
}
// Files
pub struct Files;
impl Files {
fn make<'a>(
scope: &mlua::Scope<'a, 'a>,
inner: &'a core::files::Files,
) -> mlua::Result<AnyUserData<'a>> {
LUA.register_userdata_type::<core::files::Files>(|reg| {
reg.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.len()));
reg.add_meta_function(MetaMethod::Pairs, |lua, me: AnyUserData| {
let iter = lua.create_function(|lua, (me, i): (AnyUserData, usize)| {
let items: Vec<AnyUserData> = me.named_user_value("items")?;
let i = i + 1;
Ok(if i > items.len() {
mlua::Variadic::new()
} else {
let item = items[i - 1].clone().into_lua(lua)?;
mlua::Variadic::from_iter([i.into_lua(lua)?, item])
})
})?;
Ok((iter, me, 0))
});
})?;
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value(
"items",
inner.iter().filter_map(|f| File::make(scope, f).ok()).collect::<Vec<_>>(),
)?;
Ok(ud)
}
}
// File
pub struct File;
impl File {
fn make<'a>(
scope: &mlua::Scope<'a, 'a>,
inner: &'a core::files::File,
) -> mlua::Result<AnyUserData<'a>> {
LUA.register_userdata_type::<core::files::File>(|reg| {
reg.add_field_method_get("url", |_, me| Ok(Url::from(me.url())));
reg.add_field_method_get("length", |_, me| Ok(me.length()));
reg.add_field_method_get("link_to", |_, me| {
Ok(me.link_to().map(|l| l.to_string_lossy().to_string()))
});
reg.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
// Meta
reg.add_field_method_get("permissions", |_, me| {
Ok(shared::permissions(me.meta().permissions()))
});
})?;
let ud = scope.create_any_userdata_ref(inner)?;
Ok(ud)
}
}

View file

@ -0,0 +1,7 @@
mod manager;
mod shared;
mod tasks;
pub use manager::*;
pub use shared::*;
pub use tasks::*;

View file

@ -0,0 +1,11 @@
use mlua::UserData;
// Url
pub struct Url(shared::Url);
impl From<&shared::Url> for Url {
fn from(value: &shared::Url) -> Self { Self(value.clone()) }
}
// TODO
impl UserData for Url {}

View file

@ -0,0 +1,14 @@
use mlua::{LuaSerdeExt, UserData};
// Tasks
pub struct Tasks<'a>(&'a core::tasks::Tasks);
impl<'a> Tasks<'a> {
pub fn new(tasks: &'a core::tasks::Tasks) -> Self { Self(tasks) }
}
impl<'a> UserData for Tasks<'a> {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("progress", |lua, me| lua.to_value(&me.0.progress))
}
}

View file

@ -9,14 +9,17 @@ pub struct Status;
impl Status { impl Status {
fn scope<T, F: FnOnce() -> Result<T>>(cx: &Ctx, f: F) -> Result<T> { fn scope<T, F: FnOnce() -> Result<T>>(cx: &Ctx, f: F) -> Result<T> {
// crate::Manager::register()?;
LUA.scope(|scope| { LUA.scope(|scope| {
let manager = scope.create_nonstatic_userdata(bindings::Manager::new(&cx.manager))?; let manager = crate::Manager::make(scope, &cx.manager)?;
let tasks = scope.create_nonstatic_userdata(bindings::Tasks::new(&cx.tasks))?; let tasks = scope.create_nonstatic_userdata(bindings::Tasks::new(&cx.tasks))?;
let cx = LUA.create_table()?; let cx3 = LUA.create_table()?;
cx.set("manager", manager)?; cx3.set("manager", manager)?;
cx.set("tasks", tasks)?; cx3.set("tasks", tasks)?;
GLOBALS.set("cx", cx)?;
GLOBALS.set("cx", cx3)?;
f() f()
}) })

View file

@ -76,17 +76,6 @@ pub fn readable_path(p: &Path) -> String {
p.display().to_string() p.display().to_string()
} }
pub fn readable_size(size: u64) -> String {
let units = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
let mut size = size as f64;
let mut i = 0;
while size > 1024.0 && i < units.len() - 1 {
size /= 1024.0;
i += 1;
}
format!("{:.1} {}", size, units[i])
}
pub async fn unique_path(mut p: Url) -> Url { pub async fn unique_path(mut p: Url) -> Url {
let Some(name) = p.file_name().map(|n| n.to_owned()) else { let Some(name) = p.file_name().map(|n| n.to_owned()) else {
return p; return p;