This commit is contained in:
sxyazi 2023-09-30 14:48:46 +08:00
parent 2616419858
commit 2c2e1668fc
No known key found for this signature in database
11 changed files with 177 additions and 78 deletions

View file

@ -69,24 +69,6 @@ impl<'a> Widget for Folder<'a> {
// );
// }
//
// let hovered = matches!(self.folder.hovered, Some(ref h) if h.url() ==
// f.url()); let style = if self.is_preview && hovered {
// THEME.preview.hovered.get()
// } else if hovered {
// THEME.selection.hovered.get()
// } else {
// self.item_style(f)
// };
//
// let mut spans = Vec::with_capacity(10);
// spans.push(Span::raw(format!(" {} ", Self::icon(f))));
// spans.extend(self.highlighted_item(f));
//
// if let Some(link_to) = f.link_to() {
// if MANAGER.show_symlink {
// spans.push(Span::raw(format!(" -> {}", link_to.display())));
// }
// }
//
// if let Some(idx) = active
// .finder()

View file

@ -1,12 +1,12 @@
use anyhow::bail;
use crossterm::terminal::WindowSize;
use ratatui::prelude::Rect;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use shared::Term;
use super::{FOLDER_MARGIN, PREVIEW_BORDER, PREVIEW_MARGIN};
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(try_from = "Vec<u32>")]
pub struct ManagerLayout {
pub parent: u32,

View file

@ -1,9 +1,9 @@
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use super::{ManagerLayout, SortBy};
use crate::MERGED_YAZI;
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Serialize)]
pub struct Manager {
pub layout: ManagerLayout,

View file

@ -1,7 +1,7 @@
use anyhow::bail;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
#[serde(try_from = "String")]
pub enum SortBy {
#[default]

View file

@ -1,25 +1,47 @@
Folder = {}
Folder = {
Kind = {
Parent = 0,
Current = 1,
Preview = 2,
},
}
function Folder:by_kind(kind)
if kind == self.Kind.Parent then
return cx.manager.parent
elseif kind == self.Kind.Current then
return cx.manager.current
elseif kind == self.Kind.Preview then
return cx.manager.preview.folder
end
end
function Folder:window(kind)
local folder = self:by_kind(kind)
if folder ~= nil then
return folder.files:slice(folder.offset, MANAGER.layout.folder_height())
end
end
function Folder:hovered(kind)
local folder = self:by_kind(kind)
return folder and folder.hovered
end
function Folder:parent(area)
local parent = cx.manager.parent
if parent == nil then
return ui.Paragraph(area, ui.Line {})
end
local hovered = nil
if parent.hovered ~= nil then
hovered = parent.hovered.url
local window = self:window(self.Kind.Parent)
if window == nil then
return {}
end
local hovered = (self:hovered(self.Kind.Parent) or {}).url
local lines = {}
for _, f in pairs(parent.files) do
local line = ui.Line { ui.Span(" " .. f.icon .. " " .. f.name .. " ") }
-- TODO: preview hovered
for _, f in pairs(window) do
local line = ui.Line { ui.Span(" " .. f:icon() .. " " .. f.name .. " ") }
if f.url == hovered then
line = line:style(THEME.selection.hovered)
else
line = line:style(f.style)
line = line:style(f:style())
end
lines[#lines + 1] = line
@ -29,20 +51,25 @@ function Folder:parent(area)
end
function Folder:current(area)
local hovered = nil
if cx.manager.current.hovered ~= nil then
hovered = cx.manager.current.hovered.url
local hovered = (self:hovered(self.Kind.Current) or {}).url
local lines = {}
for _, f in pairs(self:window(self.Kind.Current)) do
local name = f.name
-- Show symlink target
if MANAGER.show_symlink then
local link_to = f.link_to
if link_to ~= nil then
name = name .. " -> " .. tostring(link_to)
end
end
local lines = {}
for _, f in pairs(cx.manager.current.files) do
local line = ui.Line { ui.Span(" " .. f.icon .. " " .. f.name .. " ") }
-- TODO: preview hovered
-- Highlight hovered file
local line = ui.Line { ui.Span(" " .. f:icon() .. " " .. name .. " ") }
if f.url == hovered then
line = line:style(THEME.selection.hovered)
else
line = line:style(f.style)
line = line:style(f:style())
end
lines[#lines + 1] = line
@ -52,25 +79,32 @@ function Folder:current(area)
end
function Folder:preview(area)
local target = cx.manager.preview.folder
if target == nil then
return ui.Paragraph(area, ui.Line {})
local window = self:window(self.Kind.Preview)
if window == nil then
return {}
end
local hovered = (self:hovered(self.Kind.Preview) or {}).url
local lines = {}
for _, f in pairs(target.files) do
lines[#lines + 1] = ui.Line { ui.Span(f.name) }
for _, f in pairs(window) do
local line = ui.Line { ui.Span(" " .. f:icon() .. " " .. f.name .. " ") }
if f.url == hovered then
line = line:style(THEME.preview.hovered)
else
line = line:style(f:style())
end
lines[#lines + 1] = line
end
return { ui.Paragraph(area, lines) }
end
function Folder:render(area, args)
if args.kind == 0 then
if args.kind == self.Kind.Parent then
return self:parent(area)
elseif args.kind == 1 then
elseif args.kind == self.Kind.Current then
return self:current(area)
elseif args.kind == 2 then
elseif args.kind == self.Kind.Preview then
return self:preview(area)
end
end

View file

@ -1,10 +1,9 @@
Status = {}
function Status.style()
local mode = cx.manager.mode:upper()
if mode == "SELECT" then
if cx.manager.mode.is_select then
return THEME.status.mode_select
elseif mode == "UNSET" then
elseif cx.manager.mode.is_unset then
return THEME.status.mode_unset
else
return THEME.status.mode_normal
@ -12,7 +11,7 @@ function Status.style()
end
function Status:mode()
local mode = cx.manager.mode:upper()
local mode = tostring(cx.manager.mode):upper()
if mode == "UNSET" then
mode = "UN-SET"
end

View file

@ -1,5 +1,5 @@
use config::THEME;
use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserDataFields, UserDataMethods};
use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserDataFields, UserDataMethods, Value};
use super::Url;
use crate::{layout::Style, LUA};
@ -9,19 +9,28 @@ pub struct Manager;
impl Manager {
pub(crate) fn init() -> mlua::Result<()> {
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("parent", |_, me| me.named_user_value::<AnyUserData>("parent"));
reg.add_field_function_get("mode", |_, me| me.named_user_value::<AnyUserData>("mode"));
reg.add_field_function_get("parent", |_, me| me.named_user_value::<Value>("parent"));
reg.add_field_function_get("current", |_, me| me.named_user_value::<AnyUserData>("current"));
reg.add_field_function_get("preview", |_, me| me.named_user_value::<AnyUserData>("preview"));
})?;
LUA.register_userdata_type::<core::manager::Mode>(|reg| {
reg.add_field_method_get("is_select", |_, me| Ok(me.is_select()));
reg.add_field_method_get("is_unset", |_, me| Ok(me.is_unset()));
reg.add_field_method_get("is_visual", |_, me| Ok(me.is_visual()));
reg.add_method("pending", |_, me, (idx, state): (usize, bool)| Ok(me.pending(idx, state)));
reg.add_meta_method(MetaMethod::ToString, |_, me, ()| Ok(me.to_string()));
})?;
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_function_get("hovered", |_, me| me.named_user_value::<Value>("hovered"));
})?;
LUA.register_userdata_type::<core::files::Files>(|reg| {
@ -41,24 +50,27 @@ impl Manager {
})?;
Ok((iter, me, 0))
});
reg.add_function("slice", |_, (me, skip, take): (AnyUserData, usize, usize)| {
let items = me.named_user_value::<Vec<AnyUserData>>("items")?;
Ok(items.iter().skip(skip).take(take).cloned().collect::<Vec<_>>())
});
})?;
LUA.register_userdata_type::<core::files::File>(|reg| {
reg.add_field_method_get("name", |_, me| {
Ok(me.url().file_name().map(|n| n.to_string_lossy().to_string()))
});
reg.add_field_function_get("icon", |_, me| {
reg.add_function("icon", |_, me: AnyUserData| {
me.named_user_value::<Function>("icon")?.call::<_, String>(())
});
reg.add_field_function_get("style", |_, me| {
reg.add_function("style", |_, me: AnyUserData| {
me.named_user_value::<Function>("style")?.call::<_, Style>(())
});
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("link_to", |_, me| Ok(me.link_to().map(Url::from)));
reg.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
reg.add_field_method_get("is_hidden", |_, me| Ok(me.is_hidden()));
@ -69,7 +81,7 @@ impl Manager {
})?;
LUA.register_userdata_type::<core::manager::Preview>(|reg| {
reg.add_field_function_get("folder", |_, me| me.named_user_value::<AnyUserData>("folder"));
reg.add_field_function_get("folder", |_, me| me.named_user_value::<Value>("folder"));
})?;
Ok(())
@ -80,6 +92,7 @@ impl Manager {
inner: &'a core::manager::Manager,
) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("mode", scope.create_any_userdata_ref(inner.active().mode())?)?;
ud.set_named_user_value(
"parent",
inner.parent().and_then(|p| Self::folder(scope, inner, p).ok()),

47
plugin/src/config.rs Normal file
View file

@ -0,0 +1,47 @@
use mlua::{LuaSerdeExt, SerializeOptions, Table};
use crate::{layout::Rect, GLOBALS, LUA};
#[derive(Clone, Copy)]
pub(super) struct Config;
impl Config {
pub(super) fn install(self) -> mlua::Result<()> {
let options =
SerializeOptions::new().serialize_none_to_null(false).serialize_unit_to_null(false);
self.theme(options)?;
self.manager(options)?;
Ok(())
}
fn theme(self, options: SerializeOptions) -> mlua::Result<()> {
GLOBALS.set("THEME", LUA.to_value_with(&*config::THEME, options)?)
}
fn manager(self, options: SerializeOptions) -> mlua::Result<()> {
let manager = LUA.to_value_with(&*config::MANAGER, options)?;
{
let layout: Table = manager.as_table().unwrap().get("layout")?;
layout.set(
"preview_rect",
LUA.create_function(|_, ()| Ok(Rect(config::MANAGER.layout.preview_rect())))?,
)?;
layout.set(
"preview_height",
LUA.create_function(|_, ()| Ok(config::MANAGER.layout.preview_height()))?,
)?;
layout.set(
"folder_rect",
LUA.create_function(|_, ()| Ok(Rect(config::MANAGER.layout.folder_rect())))?,
)?;
layout.set(
"folder_height",
LUA.create_function(|_, ()| Ok(config::MANAGER.layout.folder_height()))?,
)?;
}
GLOBALS.set("MANAGER", manager)
}
}

View file

@ -1,8 +1,27 @@
use mlua::{FromLua, Lua, UserData, Value};
use mlua::{FromLua, Lua, Table, UserData, Value};
use crate::{GLOBALS, LUA};
#[derive(Clone, Copy)]
pub(crate) struct Rect(pub(crate) ratatui::layout::Rect);
impl Rect {
pub(crate) fn install() -> mlua::Result<()> {
let ui: Table = GLOBALS.get("ui")?;
ui.set(
"Rect",
LUA.create_function(|_, args: Table| {
Ok(Self(ratatui::layout::Rect {
x: args.get("x")?,
y: args.get("y")?,
width: args.get("w")?,
height: args.get("h")?,
}))
})?,
)
}
}
impl<'lua> FromLua<'lua> for Rect {
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> mlua::Result<Self> {
match value {
@ -20,7 +39,12 @@ impl UserData for Rect {
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("x", |_, me| Ok(me.0.x));
fields.add_field_method_get("y", |_, me| Ok(me.0.y));
fields.add_field_method_get("width", |_, me| Ok(me.0.width));
fields.add_field_method_get("height", |_, me| Ok(me.0.height));
fields.add_field_method_get("w", |_, me| Ok(me.0.width));
fields.add_field_method_get("h", |_, me| Ok(me.0.height));
fields.add_field_method_get("left", |_, me| Ok(me.0.left()));
fields.add_field_method_get("right", |_, me| Ok(me.0.right()));
fields.add_field_method_get("top", |_, me| Ok(me.0.top()));
fields.add_field_method_get("bottom", |_, me| Ok(me.0.bottom()));
}
}

View file

@ -2,8 +2,10 @@
mod bindings;
mod components;
mod config;
mod layout;
mod plugin;
pub use components::*;
use config::*;
pub use plugin::*;

View file

@ -1,6 +1,5 @@
use anyhow::Result;
use config::THEME;
use mlua::{Lua, LuaSerdeExt, SerializeOptions, Table};
use mlua::{Lua, Table};
use shared::RoCell;
use crate::{bindings, layout};
@ -27,17 +26,16 @@ pub fn init() {
bindings::init()?;
// Install
crate::Config.install()?;
layout::Constraint::install()?;
layout::Layout::install()?;
layout::Line::install()?;
layout::Paragraph::install()?;
layout::Rect::install()?;
layout::Span::install()?;
layout::Style::install()?;
let options =
SerializeOptions::new().serialize_none_to_null(false).serialize_unit_to_null(false);
GLOBALS.set("THEME", LUA.to_value_with(&*THEME, options)?)?;
Ok(())
}