This commit is contained in:
sxyazi 2023-09-29 11:54:06 +08:00
parent f3b82274b6
commit 2616419858
No known key found for this signature in database
5 changed files with 106 additions and 64 deletions

View file

@ -1,7 +1,6 @@
use core::{files::File, Ctx};
use core::Ctx;
use config::THEME;
use ratatui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget};
use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget};
use tracing::info;
pub(super) struct Folder<'a> {
@ -20,52 +19,24 @@ impl<'a> Folder<'a> {
}
impl<'a> Folder<'a> {
#[inline]
fn icon(file: &File) -> &'static str {
THEME
.icons
.iter()
.find(|x| x.name.match_path(file.url(), Some(file.is_dir())))
.map(|x| x.display.as_ref())
.unwrap_or("")
}
#[inline]
fn item_style(&self, file: &File) -> Style {
let mime = self.cx.manager.mimetype.get(file.url());
THEME
.filetypes
.iter()
.find(|x| x.matches(file.url(), mime, file.is_dir()))
.map(|x| x.style.into())
.unwrap_or_else(Style::new)
}
fn highlighted_item<'b>(&'b self, file: &'b File) -> Vec<Span> {
let short = short_path(file.url(), &self.folder.cwd);
let v = self.is_find.then_some(()).and_then(|_| {
let finder = self.cx.manager.active().finder()?;
#[cfg(target_os = "windows")]
let (head, body, tail) = finder.explode(short.name.to_string_lossy().as_bytes())?;
#[cfg(not(target_os = "windows"))]
let (head, body, tail) = {
use std::os::unix::ffi::OsStrExt;
finder.explode(short.name.as_bytes())?
};
// TODO: to be configured by THEME?
let style = Style::new().fg(Color::Rgb(255, 255, 50)).add_modifier(Modifier::ITALIC);
Some(vec![
Span::raw(short.prefix.join(head).display().to_string()),
Span::styled(body, style),
Span::raw(tail),
])
});
v.unwrap_or_else(|| vec![Span::raw(format!("{}", short))])
}
// fn highlighted_item<'b>(&'b self, file: &'b File) -> Vec<Span> {
// let short = short_path(file.url(), &self.folder.cwd);
//
// let v = self.is_find.then_some(()).and_then(|_| {
// let finder = self.cx.manager.active().finder()?;
// let (head, body, tail) = finder.explode(short.name)?;
//
// // TODO: to be configured by THEME?
// let style = Style::new().fg(Color::Rgb(255, 255,
// 50)).add_modifier(Modifier::ITALIC); Some(vec![
// Span::raw(short.prefix.join(head.as_ref()).display().to_string()),
// Span::styled(body, style),
// Span::raw(tail),
// ])
// });
//
// v.unwrap_or_else(|| vec![Span::raw(format!("{}", short))])
// }
}
impl<'a> Widget for Folder<'a> {

View file

@ -6,9 +6,23 @@ function Folder:parent(area)
return ui.Paragraph(area, ui.Line {})
end
local hovered = nil
if parent.hovered ~= nil then
hovered = parent.hovered.url
end
local lines = {}
for _, f in pairs(parent.files) do
lines[#lines + 1] = ui.Line { ui.Span(f.name) }
local line = ui.Line { ui.Span(" " .. f.icon .. " " .. f.name .. " ") }
-- TODO: preview hovered
if f.url == hovered then
line = line:style(THEME.selection.hovered)
else
line = line:style(f.style)
end
lines[#lines + 1] = line
end
return { ui.Paragraph(area, lines) }
@ -22,10 +36,15 @@ function Folder:current(area)
local lines = {}
for _, f in pairs(cx.manager.current.files) do
local line = ui.Line { ui.Span(f.name) }
local line = ui.Line { ui.Span(" " .. f.icon .. " " .. f.name .. " ") }
-- TODO: preview hovered
if f.url == hovered then
line = line:style(THEME.selection.hovered)
else
line = line:style(f.style)
end
lines[#lines + 1] = line
end

View file

@ -1,7 +1,8 @@
use mlua::{AnyUserData, IntoLua, MetaMethod, UserDataFields, UserDataMethods};
use config::THEME;
use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserDataFields, UserDataMethods};
use super::Url;
use crate::LUA;
use crate::{layout::Style, LUA};
pub struct Manager;
@ -46,6 +47,13 @@ impl Manager {
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| {
me.named_user_value::<Function>("icon")?.call::<_, String>(())
});
reg.add_field_function_get("style", |_, me| {
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| {
@ -72,22 +80,26 @@ impl Manager {
inner: &'a core::manager::Manager,
) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("parent", inner.parent().and_then(|p| Self::folder(scope, p).ok()))?;
ud.set_named_user_value("current", Self::folder(scope, inner.current())?)?;
ud.set_named_user_value("preview", Self::preview(scope, inner.active())?)?;
ud.set_named_user_value(
"parent",
inner.parent().and_then(|p| Self::folder(scope, inner, p).ok()),
)?;
ud.set_named_user_value("current", Self::folder(scope, inner, inner.current())?)?;
ud.set_named_user_value("preview", Self::preview(scope, inner, inner.active())?)?;
Ok(ud)
}
pub(crate) fn folder<'a>(
scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
inner: &'a core::manager::Folder,
) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("files", Self::files(scope, &inner.files)?)?;
ud.set_named_user_value("files", Self::files(scope, manager, &inner.files)?)?;
ud.set_named_user_value(
"hovered",
inner.hovered.as_ref().and_then(|h| Self::file(scope, h).ok()),
inner.hovered.as_ref().and_then(|h| Self::file(scope, manager, h).ok()),
)?;
Ok(ud)
@ -95,12 +107,13 @@ impl Manager {
fn files<'a>(
scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
inner: &'a core::files::Files,
) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value(
"items",
inner.iter().filter_map(|f| Self::file(scope, f).ok()).collect::<Vec<_>>(),
inner.iter().filter_map(|f| Self::file(scope, manager, f).ok()).collect::<Vec<_>>(),
)?;
Ok(ud)
@ -108,13 +121,44 @@ impl Manager {
fn file<'a>(
scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
inner: &'a core::files::File,
) -> mlua::Result<AnyUserData<'a>> {
scope.create_any_userdata_ref(inner)
let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value(
"icon",
scope.create_function(|_, ()| {
Ok(
THEME
.icons
.iter()
.find(|&x| x.name.match_path(inner.url(), Some(inner.is_dir())))
.map(|x| x.display.to_string()),
)
})?,
)?;
ud.set_named_user_value(
"style",
scope.create_function(|_, ()| {
let mime = manager.mimetype.get(inner.url());
Ok(
THEME
.filetypes
.iter()
.find(|&x| x.matches(inner.url(), mime, inner.is_dir()))
.map(|x| Style::from(x.style)),
)
})?,
)?;
Ok(ud)
}
fn preview<'a>(
scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
tab: &'a core::manager::Tab,
) -> mlua::Result<AnyUserData<'a>> {
let inner = tab.preview();
@ -127,7 +171,7 @@ impl Manager {
.as_ref()
.filter(|l| l.is_folder())
.and_then(|l| tab.history(&l.url))
.and_then(|f| Self::folder(scope, f).ok()),
.and_then(|f| Self::folder(scope, manager, f).ok()),
)?;
Ok(ud)

View file

@ -50,11 +50,15 @@ impl<'lua> FromLua<'lua> for Line {
impl UserData for Line {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("style", |_, (ud, style): (AnyUserData, Style)| {
methods.add_function("style", |_, (ud, value): (AnyUserData, Value)| {
{
let mut me = ud.borrow_mut::<Self>()?;
me.0.reset_style();
me.0.patch_style(style.0);
match value {
Value::Nil => me.0.reset_style(),
Value::Table(tbl) => me.0.patch_style(Style::from(tbl).0),
Value::UserData(ud) => me.0.patch_style(ud.borrow::<Style>()?.0),
_ => return Err(mlua::Error::external("expected a Style or Table or nil")),
};
}
Ok(ud)
});

View file

@ -14,6 +14,10 @@ impl Style {
}
}
impl From<config::theme::Style> for Style {
fn from(value: config::theme::Style) -> Self { Self(value.into()) }
}
impl<'a> From<Table<'a>> for Style {
fn from(value: Table) -> Self {
let mut style = ratatui::style::Style::default();