This commit is contained in:
sxyazi 2023-10-05 18:20:35 +08:00
parent a3971fc4f5
commit 46c54f6bad
No known key found for this signature in database
26 changed files with 175 additions and 139 deletions

View file

@ -1,4 +1,4 @@
use core::{emit, files::FilesSorter, input::InputMode, manager::FinderCase};
use core::{emit, files::FilesSorter, input::InputMode, manager::FinderCase, Ctx};
use config::{keymap::{Control, Exec, Key, KeymapLayer}, manager::SortBy, KEYMAP};
use shared::{optional_bool, Url};

View file

@ -17,7 +17,7 @@ impl<'a> Widget for Layout<'a> {
fn render(self, area: Rect, buf: &mut Buffer) {
let chunks = layout::Layout::new()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
.split(area);
let cwd = &self.cx.manager.current().cwd;

View file

@ -16,7 +16,7 @@ impl<'a> Widget for Layout<'a> {
fn render(self, area: Rect, buf: &mut Buffer) {
let chunks = layout::Layout::new()
.direction(Direction::Vertical)
.constraints([Constraint::Min(0), Constraint::Length(1)].as_ref())
.constraints([Constraint::Min(0), Constraint::Length(1)])
.split(area);
Clear.render(area, buf);

View file

@ -1,10 +1,7 @@
use core::Ctx;
use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget};
use tracing::info;
pub(super) struct Folder<'a> {
cx: &'a Ctx,
pub(super) struct Folder {
kind: FolderKind,
}
@ -14,11 +11,11 @@ pub(super) enum FolderKind {
Preview = 2,
}
impl<'a> Folder<'a> {
pub(super) fn new(cx: &'a Ctx, kind: FolderKind) -> Self { Self { cx, kind } }
impl Folder {
pub(super) fn new(kind: FolderKind) -> Self { Self { kind } }
}
impl<'a> Folder<'a> {
impl Folder {
// fn highlighted_item<'b>(&'b self, file: &'b File) -> Vec<Span> {
// let short = short_path(file.url(), &self.folder.cwd);
//
@ -39,7 +36,7 @@ impl<'a> Folder<'a> {
// }
}
impl<'a> Widget for Folder<'a> {
impl Widget for Folder {
fn render(self, area: Rect, buf: &mut Buffer) {
let x = plugin::Folder { kind: self.kind as u8 }.render(area);
if x.is_err() {
@ -55,21 +52,6 @@ impl<'a> Widget for Folder<'a> {
// .iter()
// .enumerate()
// .map(|(i, f)| {
// let is_selected = self.folder.files.is_selected(f.url());
// if (!self.is_selection && is_selected)
// || (self.is_selection && mode.pending(self.folder.offset() + i, is_selected))
// {
// buf.set_style(
// Rect { x: area.x.saturating_sub(1), y: i as u16 + 1, width: 1, height: 1
// }, if self.is_selection {
// THEME.marker.selecting.get()
// } else {
// THEME.marker.selected.get()
// },
// );
// }
//
//
// if let Some(idx) = active
// .finder()
// .filter(|&f| hovered && self.is_find && f.has_matched())

View file

@ -20,25 +20,22 @@ impl<'a> Widget for Layout<'a> {
let chunks = layout::Layout::new()
.direction(Direction::Horizontal)
.constraints(
[
Constraint::Ratio(layout.parent, layout.all),
Constraint::Ratio(layout.current, layout.all),
Constraint::Ratio(layout.preview, layout.all),
]
.as_ref(),
)
.constraints([
Constraint::Ratio(layout.parent, layout.all),
Constraint::Ratio(layout.current, layout.all),
Constraint::Ratio(layout.preview, layout.all),
])
.split(area);
// Parent
let block = Block::new().borders(Borders::RIGHT).padding(Padding::new(1, 0, 0, 0));
if manager.parent().is_some() {
Folder::new(self.cx, FolderKind::Parent).render(block.inner(chunks[0]), buf);
Folder::new(FolderKind::Parent).render(block.inner(chunks[0]), buf);
}
block.render(chunks[0], buf);
// Current
Folder::new(self.cx, FolderKind::Current).render(chunks[1], buf);
Folder::new(FolderKind::Current).render(chunks[1], buf);
// Preview
let block = Block::new().borders(Borders::LEFT).padding(Padding::new(0, 1, 0, 0));

View file

@ -27,7 +27,7 @@ impl<'a> Widget for Preview<'a> {
match &preview.lock.as_ref().unwrap().data {
PreviewData::Folder => {
Folder::new(self.cx, FolderKind::Preview).render(area, buf);
Folder::new(FolderKind::Preview).render(area, buf);
}
PreviewData::Text(s) => {
let p = Paragraph::new(s.as_bytes().into_text().unwrap());

View file

@ -17,12 +17,12 @@ impl<'a> Widget for Root<'a> {
fn render(self, area: Rect, buf: &mut Buffer) {
let chunks = Layout::new()
.direction(Direction::Vertical)
.constraints([Constraint::Length(1), Constraint::Min(0), Constraint::Length(1)].as_ref())
.constraints([Constraint::Length(1), Constraint::Min(0), Constraint::Length(1)])
.split(area);
header::Layout::new(self.cx).render(chunks[0], buf);
manager::Layout::new(self.cx).render(chunks[1], buf);
status::Layout::new(self.cx).render(chunks[2], buf);
status::Layout.render(chunks[2], buf);
if self.cx.tasks.visible {
tasks::Layout::new(self.cx).render(area, buf);

View file

@ -1,17 +1,9 @@
use core::Ctx;
use ratatui::{buffer::Buffer, prelude::Rect, widgets::Widget};
use tracing::info;
pub(crate) struct Layout<'a> {
cx: &'a Ctx,
}
pub(crate) struct Layout;
impl<'a> Layout<'a> {
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
}
impl<'a> Widget for Layout<'a> {
impl Widget for Layout {
fn render(self, area: Rect, buf: &mut Buffer) {
let x = plugin::Status::render(area);
if x.is_err() {

View file

@ -14,29 +14,21 @@ impl<'a> Layout<'a> {
pub(super) fn area(area: Rect) -> Rect {
let chunk = layout::Layout::new()
.direction(Direction::Vertical)
.constraints(
[
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
Constraint::Percentage(TASKS_PERCENT),
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
]
.as_ref(),
)
.constraints([
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
Constraint::Percentage(TASKS_PERCENT),
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
])
.split(area)[1];
let chunk = layout::Layout::new()
layout::Layout::new()
.direction(Direction::Horizontal)
.constraints(
[
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
Constraint::Percentage(TASKS_PERCENT),
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
]
.as_ref(),
)
.split(chunk)[1];
chunk
.constraints([
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
Constraint::Percentage(TASKS_PERCENT),
Constraint::Percentage((100 - TASKS_PERCENT) / 2),
])
.split(chunk)[1]
}
}

View file

@ -35,9 +35,7 @@ impl Widget for Which<'_> {
let chunks = layout::Layout::new()
.direction(Direction::Horizontal)
.constraints(
[Constraint::Ratio(1, 3), Constraint::Ratio(1, 3), Constraint::Ratio(1, 3)].as_ref(),
)
.constraints([Constraint::Ratio(1, 3), Constraint::Ratio(1, 3), Constraint::Ratio(1, 3)])
.split(area);
Clear.render(area, buf);

View file

@ -23,12 +23,13 @@ permissions_r = { fg = "#F3D398" }
permissions_w = { fg = "#FA7F94" }
permissions_x = { fg = "#7AD9E5" }
[selection]
[files]
hovered = { fg = "#1E2031", bg = "#80AEFA" }
[marker]
selecting = { fg = "#97DC8D", bg = "#97DC8D" }
selected = { fg = "#F3D398", bg = "#F3D398" }
selected = { fg = "#97DC8D", bg = "#97DC8D" }
copied = { fg = "#F3D398", bg = "#F3D398" }
cut = { fg = "#FF84A9", bg = "#FF84A9" }
[preview]
hovered = { underline = true }

View file

@ -3,12 +3,13 @@ use serde::{Deserialize, Serialize};
use super::Style;
#[derive(Deserialize, Serialize)]
pub struct Selection {
pub struct Files {
pub hovered: Style,
}
#[derive(Deserialize, Serialize)]
pub struct Marker {
pub selecting: Style,
pub selected: Style,
pub selected: Style,
pub copied: Style,
pub cut: Style,
}

View file

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use shared::expand_path;
use validator::Validate;
use super::{Filetype, Icon, Marker, Selection, Status, Style};
use super::{Files, Filetype, Icon, Marker, Status, Style};
use crate::{validation::check_validation, MERGED_THEME};
#[derive(Deserialize, Serialize, Validate)]
@ -25,7 +25,7 @@ pub struct Preview {
pub struct Theme {
pub tab: Tab,
pub status: Status,
pub selection: Selection,
pub files: Files,
pub marker: Marker,
pub preview: Preview,
#[serde(rename = "filetype", deserialize_with = "Filetype::deserialize", skip_serializing)]

View file

@ -10,9 +10,9 @@ use super::{Backstack, Finder, FinderCase, Folder, Mode, Preview, PreviewLock};
use crate::{emit, external::{self, FzfOpt, ZoxideOpt}, files::{File, FilesOp, FilesSorter}, input::InputOpt, Event, Step, BLOCKER};
pub struct Tab {
pub(super) mode: Mode,
pub(super) current: Folder,
pub(super) parent: Option<Folder>,
pub mode: Mode,
pub current: Folder,
pub parent: Option<Folder>,
pub(super) backstack: Backstack<Url>,
pub(super) history: BTreeMap<Url, Folder>,
@ -455,14 +455,10 @@ impl Tab {
impl Tab {
// --- Mode
#[inline]
pub fn mode(&self) -> &Mode { &self.mode }
#[inline]
pub fn in_selecting(&self) -> bool {
self.mode().is_visual() || self.current.files.has_selected()
}
pub fn in_selecting(&self) -> bool { self.mode.is_visual() || self.current.files.has_selected() }
// --- Current
// TODO: remove this
#[inline]
pub fn name(&self) -> &str {
self
@ -475,10 +471,9 @@ impl Tab {
}
pub fn selected(&self) -> Vec<&File> {
let mode = self.mode();
let pending = mode.visual().map(|(_, p)| Cow::Borrowed(p)).unwrap_or_default();
let pending = self.mode.visual().map(|(_, p)| Cow::Borrowed(p)).unwrap_or_default();
let selected = self.current.files.selected(&pending, self.mode.is_unset());
let selected = self.current.files.selected(&pending, mode.is_unset());
if selected.is_empty() {
self.current.hovered.as_ref().map(|h| vec![h]).unwrap_or_default()
} else {

View file

@ -1 +1 @@
{"language":"en","version":"0.2","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","natsort"]}
{"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","natsort","backstack","luajit"],"language":"en","version":"0.2"}

View file

@ -10,6 +10,6 @@ shared = { path = "../shared" }
# External dependencies
anyhow = "^1"
mlua = { version = "^0", features = [ "lua54", "vendored", "serialize" ] }
mlua = { version = "^0", features = [ "luajit52", "vendored", "serialize" ] }
tracing = "^0"
ratatui = "^0"

View file

@ -8,11 +8,11 @@ Folder = {
function Folder:by_kind(kind)
if kind == self.Kind.Parent then
return cx.manager.parent
return cx.active.parent
elseif kind == self.Kind.Current then
return cx.manager.current
return cx.active.current
elseif kind == self.Kind.Preview then
return cx.manager.preview.folder
return cx.active.preview.folder
end
end
@ -20,6 +20,36 @@ function Folder:window(kind) return (self:by_kind(kind) or {}).window end
function Folder:hovered(kind) return (self:by_kind(kind) or {}).hovered end
function Folder:markers(area, markers)
if #markers == 0 then
return {}
end
local elements = {}
local append = function(last)
local rect = ui.Rect {
x = area.x - 1,
y = area.y + last[1] - 1,
w = 1,
h = 1 + last[2] - last[1],
}
elements[#elements + 1] = ui.Paragraph(rect, {}):style(THEME.marker.selected)
end
local last = { markers[1][1], markers[1][1], markers[1][2] } -- start, end, type
for _, m in ipairs(markers) do
if m[1] - last[2] > 1 or last[3] ~= m[2] then
append(last)
last = { m[1], m[1], m[2] }
else
last[2] = m[1]
end
end
append(last)
return elements
end
function Folder:parent(area)
local window = self:window(self.Kind.Parent)
if window == nil then
@ -28,10 +58,10 @@ function Folder:parent(area)
local hovered = (self:hovered(self.Kind.Parent) or {}).url
local lines = {}
for _, f in pairs(window) do
for _, f in ipairs(window) do
local line = ui.Line { ui.Span(" " .. f:icon() .. " " .. f.name .. " ") }
if f.url == hovered then
line = line:style(THEME.selection.hovered)
line = line:style(THEME.files.hovered)
else
line = line:style(f:style())
end
@ -44,8 +74,9 @@ end
function Folder:current(area)
local hovered = (self:hovered(self.Kind.Current) or {}).url
local markers = {}
local lines = {}
for _, f in pairs(self:window(self.Kind.Current)) do
for i, f in ipairs(self:window(self.Kind.Current)) do
local name = f.name
-- Show symlink target
@ -59,15 +90,19 @@ function Folder:current(area)
-- Highlight hovered file
local line = ui.Line { ui.Span(" " .. f:icon() .. " " .. name .. " ") }
if f.url == hovered then
line = line:style(THEME.selection.hovered)
line = line:style(THEME.files.hovered)
else
line = line:style(f:style())
end
lines[#lines + 1] = line
-- Mark selected/yanked files
if f:selected() then
markers[#markers + 1] = { i, 1 }
end
end
return { ui.Paragraph(area, lines) }
return { ui.Paragraph(area, lines), table.unpack(self:markers(area, markers)) }
end
function Folder:preview(area)
@ -78,7 +113,7 @@ function Folder:preview(area)
local hovered = (self:hovered(self.Kind.Preview) or {}).url
local lines = {}
for _, f in pairs(window) do
for _, f in ipairs(window) do
local line = ui.Line { ui.Span(" " .. f:icon() .. " " .. f.name .. " ") }
if f.url == hovered then
line = line:style(THEME.preview.hovered)

View file

@ -1,9 +1,9 @@
Status = {}
function Status.style()
if cx.manager.mode.is_select then
if cx.active.mode.is_select then
return THEME.status.mode_select
elseif cx.manager.mode.is_unset then
elseif cx.active.mode.is_unset then
return THEME.status.mode_unset
else
return THEME.status.mode_normal
@ -11,7 +11,7 @@ function Status.style()
end
function Status:mode()
local mode = tostring(cx.manager.mode):upper()
local mode = tostring(cx.active.mode):upper()
if mode == "UNSET" then
mode = "UN-SET"
end
@ -24,7 +24,7 @@ function Status:mode()
end
function Status:size()
local h = cx.manager.current.hovered
local h = cx.active.current.hovered
if h == nil then
return ui.Span("")
end
@ -37,7 +37,7 @@ function Status:size()
end
function Status:name()
local h = cx.manager.current.hovered
local h = cx.active.current.hovered
if h == nil then
return ui.Span("")
end
@ -46,7 +46,7 @@ function Status:name()
end
function Status:permissions()
local h = cx.manager.current.hovered
local h = cx.active.current.hovered
if h == nil or h.permissions == nil then
return ui.Span("")
end
@ -69,8 +69,8 @@ end
function Status:percentage()
local percent = 0
local cursor = cx.manager.current.cursor
local length = #cx.manager.current.files
local cursor = cx.active.current.cursor
local length = #cx.active.current.files
if cursor ~= 0 and length ~= 0 then
percent = math.floor((cursor + 1) * 100 / length)
end
@ -89,8 +89,8 @@ function Status:percentage()
end
function Status:position()
local cursor = cx.manager.current.cursor
local length = #cx.manager.current.files
local cursor = cx.active.current.cursor
local length = #cx.active.current.files
local style = self.style()
return ui.Line {

View file

@ -1,5 +1,5 @@
pub fn init() -> mlua::Result<()> {
super::manager::Manager::init()?;
super::tab::Tab::init()?;
super::tasks::Tasks::init()?;
Ok(())

View file

@ -1,11 +1,11 @@
#![allow(clippy::module_inception)]
mod bindings;
mod manager;
mod shared;
mod tab;
mod tasks;
pub use bindings::*;
pub use manager::*;
pub use shared::*;
pub use tab::*;
pub use tasks::*;

View file

@ -1,3 +1,5 @@
use core::Ctx;
use config::{MANAGER, THEME};
use mlua::{AnyUserData, Function, IntoLua, MetaMethod, UserData, UserDataFields, UserDataMethods, Value};
@ -20,14 +22,16 @@ impl UserData for File {
}
}
pub struct Manager<'a, 'b> {
pub struct Tab<'a, 'b> {
scope: &'b mlua::Scope<'a, 'a>,
inner: &'a core::manager::Manager,
cx: &'a core::Ctx,
inner: &'a core::manager::Tab,
}
impl<'a, 'b> Manager<'a, 'b> {
impl<'a, 'b> Tab<'a, 'b> {
pub(crate) fn init() -> mlua::Result<()> {
LUA.register_userdata_type::<core::manager::Manager>(|reg| {
LUA.register_userdata_type::<core::manager::Tab>(|reg| {
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"));
@ -85,6 +89,9 @@ impl<'a, 'b> Manager<'a, 'b> {
reg.add_function("style", |_, me: AnyUserData| {
me.named_user_value::<Function>("style")?.call::<_, Style>(())
});
reg.add_function("selected", |_, me: AnyUserData| {
me.named_user_value::<Function>("selected")?.call::<_, bool>(me)
});
reg.add_field_method_get("url", |_, me| Ok(Url::from(me.url())));
reg.add_field_method_get("length", |_, me| Ok(me.length()));
@ -105,19 +112,24 @@ impl<'a, 'b> Manager<'a, 'b> {
Ok(())
}
pub(crate) fn new(scope: &'b mlua::Scope<'a, 'a>, inner: &'a core::manager::Manager) -> Self {
Self { scope, inner }
pub(crate) fn new(
scope: &'b mlua::Scope<'a, 'a>,
cx: &'a Ctx,
inner: &'a core::manager::Tab,
) -> Self {
Self { scope, cx, inner }
}
pub(crate) fn make(&self) -> mlua::Result<AnyUserData<'a>> {
let ud = self.scope.create_any_userdata_ref(self.inner)?;
ud.set_named_user_value("mode", self.scope.create_any_userdata_ref(&self.inner.mode)?)?;
ud.set_named_user_value(
"mode",
self.scope.create_any_userdata_ref(self.inner.active().mode())?,
"parent",
self.inner.parent.as_ref().and_then(|p| self.folder(p, None).ok()),
)?;
ud.set_named_user_value("parent", self.inner.parent().and_then(|p| self.folder(p, None).ok()))?;
ud.set_named_user_value("current", self.folder(self.inner.current(), None)?)?;
ud.set_named_user_value("preview", self.preview(self.inner.active())?)?;
ud.set_named_user_value("current", self.folder(&self.inner.current, None)?)?;
ud.set_named_user_value("preview", self.preview(self.inner)?)?;
Ok(ud)
}
@ -137,11 +149,16 @@ impl<'a, 'b> Manager<'a, 'b> {
.iter()
.skip(window.0)
.take(window.1)
.filter_map(|f| self.file(f).ok())
.enumerate()
.filter_map(|(i, f)| self.file(i, f, inner).ok())
.collect::<Vec<_>>(),
)?;
ud.set_named_user_value("files", self.files(&inner.files)?)?;
ud.set_named_user_value("hovered", inner.hovered.as_ref().and_then(|h| self.file(h).ok()))?;
// TODO: remove this
ud.set_named_user_value(
"hovered",
inner.hovered.as_ref().and_then(|h| self.file(999, h, inner).ok()),
)?;
Ok(ud)
}
@ -150,8 +167,15 @@ impl<'a, 'b> Manager<'a, 'b> {
self.scope.create_any_userdata_ref(inner)
}
fn file(&self, inner: &'a core::files::File) -> mlua::Result<AnyUserData<'a>> {
fn file(
&self,
idx: usize,
inner: &'a core::files::File,
folder: &'a core::manager::Folder,
) -> mlua::Result<AnyUserData<'a>> {
let ud = self.scope.create_any_userdata_ref(inner)?;
ud.set_named_user_value("idx", idx)?;
ud.set_named_user_value(
"icon",
self.scope.create_function(|_, ()| {
@ -168,7 +192,7 @@ impl<'a, 'b> Manager<'a, 'b> {
ud.set_named_user_value(
"style",
self.scope.create_function(|_, ()| {
let mime = self.inner.mimetype.get(inner.url());
let mime = self.cx.manager.mimetype.get(inner.url());
Ok(
THEME
.filetypes
@ -179,6 +203,20 @@ impl<'a, 'b> Manager<'a, 'b> {
})?,
)?;
ud.set_named_user_value(
"selected",
self.scope.create_function(|_, me: AnyUserData| {
let is_visual = self.inner.mode.is_visual();
let selected = folder.files.is_selected(inner.url());
Ok(if !is_visual {
selected
} else {
let idx: usize = me.named_user_value("idx")?;
self.inner.mode.pending(folder.offset() + idx, selected)
})
})?,
)?;
Ok(ud)
}

View file

@ -58,7 +58,7 @@ impl UserData for Line {
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

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

View file

@ -1,6 +1,5 @@
use config::theme::Color;
use mlua::{AnyUserData, FromLua, Lua, Table, UserData, UserDataMethods, Value};
use tracing::info;
use crate::{GLOBALS, LUA};
@ -51,7 +50,6 @@ impl UserData for Style {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("fg", |_, (ud, color): (AnyUserData, String)| {
ud.borrow_mut::<Self>()?.0.fg = Color::try_from(color).ok().map(Into::into);
info!("fg: {:?}", ud.borrow::<Self>()?.0.fg);
Ok(ud)
});
methods.add_function("bg", |_, (ud, color): (AnyUserData, String)| {

View file

@ -5,7 +5,7 @@ use crate::{bindings, GLOBALS, LUA};
pub fn scope<F: FnOnce()>(cx: &Ctx, f: F) {
let _ = LUA.scope(|scope| {
let tbl = LUA.create_table()?;
tbl.set("manager", bindings::Manager::new(scope, &cx.manager).make()?)?;
tbl.set("active", bindings::Tab::new(scope, cx, cx.manager.active()).make()?)?;
tbl.set("tasks", bindings::Tasks::make(scope, &cx.tasks)?)?;
GLOBALS.set("cx", tbl)?;

View file

@ -92,7 +92,6 @@ pub fn copy_with_progress(from: &Path, to: &Path) -> mpsc::Receiver<Result<u64,
}
// Convert a file mode to a string representation
#[cfg(unix)]
#[allow(clippy::collapsible_else_if)]
pub fn permissions(permissions: Permissions) -> Option<String> {
#[cfg(windows)]