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

View file

@ -6,9 +6,23 @@ function Folder:parent(area)
return ui.Paragraph(area, ui.Line {}) return ui.Paragraph(area, ui.Line {})
end end
local hovered = nil
if parent.hovered ~= nil then
hovered = parent.hovered.url
end
local lines = {} local lines = {}
for _, f in pairs(parent.files) do 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 end
return { ui.Paragraph(area, lines) } return { ui.Paragraph(area, lines) }
@ -22,10 +36,15 @@ function Folder:current(area)
local lines = {} local lines = {}
for _, f in pairs(cx.manager.current.files) do 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 if f.url == hovered then
line = line:style(THEME.selection.hovered) line = line:style(THEME.selection.hovered)
else
line = line:style(f.style)
end end
lines[#lines + 1] = line lines[#lines + 1] = line
end 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 super::Url;
use crate::LUA; use crate::{layout::Style, LUA};
pub struct Manager; pub struct Manager;
@ -46,6 +47,13 @@ impl Manager {
reg.add_field_method_get("name", |_, me| { reg.add_field_method_get("name", |_, me| {
Ok(me.url().file_name().map(|n| n.to_string_lossy().to_string())) 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("url", |_, me| Ok(Url::from(me.url())));
reg.add_field_method_get("length", |_, me| Ok(me.length())); reg.add_field_method_get("length", |_, me| Ok(me.length()));
reg.add_field_method_get("link_to", |_, me| { reg.add_field_method_get("link_to", |_, me| {
@ -72,22 +80,26 @@ impl Manager {
inner: &'a core::manager::Manager, inner: &'a core::manager::Manager,
) -> mlua::Result<AnyUserData<'a>> { ) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?; 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(
ud.set_named_user_value("current", Self::folder(scope, inner.current())?)?; "parent",
ud.set_named_user_value("preview", Self::preview(scope, inner.active())?)?; 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) Ok(ud)
} }
pub(crate) fn folder<'a>( pub(crate) fn folder<'a>(
scope: &mlua::Scope<'a, 'a>, scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
inner: &'a core::manager::Folder, inner: &'a core::manager::Folder,
) -> mlua::Result<AnyUserData<'a>> { ) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?; 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( ud.set_named_user_value(
"hovered", "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) Ok(ud)
@ -95,12 +107,13 @@ impl Manager {
fn files<'a>( fn files<'a>(
scope: &mlua::Scope<'a, 'a>, scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
inner: &'a core::files::Files, inner: &'a core::files::Files,
) -> mlua::Result<AnyUserData<'a>> { ) -> mlua::Result<AnyUserData<'a>> {
let ud = scope.create_any_userdata_ref(inner)?; let ud = scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value( ud.set_named_user_value(
"items", "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) Ok(ud)
@ -108,13 +121,44 @@ impl Manager {
fn file<'a>( fn file<'a>(
scope: &mlua::Scope<'a, 'a>, scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
inner: &'a core::files::File, inner: &'a core::files::File,
) -> mlua::Result<AnyUserData<'a>> { ) -> 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>( fn preview<'a>(
scope: &mlua::Scope<'a, 'a>, scope: &mlua::Scope<'a, 'a>,
manager: &'a core::manager::Manager,
tab: &'a core::manager::Tab, tab: &'a core::manager::Tab,
) -> mlua::Result<AnyUserData<'a>> { ) -> mlua::Result<AnyUserData<'a>> {
let inner = tab.preview(); let inner = tab.preview();
@ -127,7 +171,7 @@ impl Manager {
.as_ref() .as_ref()
.filter(|l| l.is_folder()) .filter(|l| l.is_folder())
.and_then(|l| tab.history(&l.url)) .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) Ok(ud)

View file

@ -50,11 +50,15 @@ impl<'lua> FromLua<'lua> for Line {
impl UserData for Line { impl UserData for Line {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { 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>()?; let mut me = ud.borrow_mut::<Self>()?;
me.0.reset_style(); match value {
me.0.patch_style(style.0); 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) 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 { impl<'a> From<Table<'a>> for Style {
fn from(value: Table) -> Self { fn from(value: Table) -> Self {
let mut style = ratatui::style::Style::default(); let mut style = ratatui::style::Style::default();