mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: new Manager component for better style extensions (#284)
This commit is contained in:
parent
952c3009e6
commit
a45a8642b2
26 changed files with 347 additions and 200 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1357,6 +1357,7 @@ dependencies = [
|
||||||
name = "plugin"
|
name = "plugin"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ansi-to-tui",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"config",
|
"config",
|
||||||
"core",
|
"core",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ mod executor;
|
||||||
mod help;
|
mod help;
|
||||||
mod input;
|
mod input;
|
||||||
mod logs;
|
mod logs;
|
||||||
mod manager;
|
|
||||||
mod root;
|
mod root;
|
||||||
mod select;
|
mod select;
|
||||||
mod signals;
|
mod signals;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget};
|
|
||||||
use tracing::error;
|
|
||||||
|
|
||||||
pub(super) enum Folder {
|
|
||||||
Parent = 0,
|
|
||||||
Current = 1,
|
|
||||||
Preview = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for Folder {
|
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
||||||
let folder = plugin::Folder { kind: self as u8 };
|
|
||||||
if let Err(e) = folder.render(area, buf) {
|
|
||||||
error!("{:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
use core::Ctx;
|
|
||||||
|
|
||||||
use config::{MANAGER, THEME};
|
|
||||||
use plugin::layout::Bar;
|
|
||||||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::{Block, Borders, Padding, Widget}};
|
|
||||||
|
|
||||||
use super::{Folder, Preview};
|
|
||||||
|
|
||||||
pub(crate) struct Layout<'a> {
|
|
||||||
cx: &'a Ctx,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Layout<'a> {
|
|
||||||
pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Widget for Layout<'a> {
|
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
|
||||||
let layout = &MANAGER.layout;
|
|
||||||
let manager = &self.cx.manager;
|
|
||||||
|
|
||||||
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),
|
|
||||||
])
|
|
||||||
.split(area);
|
|
||||||
|
|
||||||
// Parent
|
|
||||||
Bar::new(chunks[0], Borders::RIGHT)
|
|
||||||
.symbol(&THEME.manager.border_symbol)
|
|
||||||
.style(THEME.manager.border_style.into())
|
|
||||||
.render(buf);
|
|
||||||
if manager.parent().is_some() {
|
|
||||||
Folder::Parent.render(Block::new().padding(Padding::new(1, 1, 0, 0)).inner(chunks[0]), buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Current
|
|
||||||
Folder::Current.render(chunks[1], buf);
|
|
||||||
|
|
||||||
// Preview
|
|
||||||
Bar::new(chunks[2], Borders::LEFT)
|
|
||||||
.symbol(&THEME.manager.border_symbol)
|
|
||||||
.style(THEME.manager.border_style.into())
|
|
||||||
.render(buf);
|
|
||||||
Preview::new(self.cx)
|
|
||||||
.render(Block::new().padding(Padding::new(1, 1, 0, 0)).inner(chunks[2]), buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
mod folder;
|
|
||||||
mod layout;
|
|
||||||
mod preview;
|
|
||||||
|
|
||||||
use folder::*;
|
|
||||||
pub(super) use layout::*;
|
|
||||||
use preview::*;
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use core::Ctx;
|
use core::Ctx;
|
||||||
|
|
||||||
|
use plugin::components;
|
||||||
use ratatui::{buffer::Buffer, layout::{Constraint, Direction, Layout, Rect}, widgets::Widget};
|
use ratatui::{buffer::Buffer, layout::{Constraint, Direction, Layout, Rect}, widgets::Widget};
|
||||||
use tracing::error;
|
|
||||||
|
|
||||||
use super::{input, manager, select, tasks, which};
|
use super::{input, select, tasks, which};
|
||||||
use crate::help;
|
use crate::help;
|
||||||
|
|
||||||
pub(super) struct Root<'a> {
|
pub(super) struct Root<'a> {
|
||||||
|
|
@ -21,13 +21,9 @@ impl<'a> Widget for Root<'a> {
|
||||||
.constraints([Constraint::Length(1), Constraint::Min(0), Constraint::Length(1)])
|
.constraints([Constraint::Length(1), Constraint::Min(0), Constraint::Length(1)])
|
||||||
.split(area);
|
.split(area);
|
||||||
|
|
||||||
if let Err(e) = plugin::Header.render(chunks[0], buf) {
|
components::Header::new(self.cx).render(chunks[0], buf);
|
||||||
error!("{:?}", e);
|
components::Manager::new(self.cx).render(chunks[1], buf);
|
||||||
}
|
components::Status::new(self.cx).render(chunks[2], buf);
|
||||||
manager::Layout::new(self.cx).render(chunks[1], buf);
|
|
||||||
if let Err(e) = plugin::Status.render(chunks[2], buf) {
|
|
||||||
error!("{:?}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.cx.tasks.visible {
|
if self.cx.tasks.visible {
|
||||||
tasks::Layout::new(self.cx).render(area, buf);
|
tasks::Layout::new(self.cx).render(area, buf);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ core = { path = "../core" }
|
||||||
shared = { path = "../shared" }
|
shared = { path = "../shared" }
|
||||||
|
|
||||||
# External dependencies
|
# External dependencies
|
||||||
|
ansi-to-tui = "^3"
|
||||||
anyhow = "^1"
|
anyhow = "^1"
|
||||||
mlua = { version = "^0", features = [ "luajit52", "vendored", "serialize" ] }
|
mlua = { version = "^0", features = [ "luajit52", "vendored", "serialize" ] }
|
||||||
ratatui = "^0"
|
ratatui = "^0"
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
Folder = {
|
Folder = {
|
||||||
Kind = {
|
PARENT = 0,
|
||||||
Parent = 0,
|
CURRENT = 1,
|
||||||
Current = 1,
|
PREVIEW = 2,
|
||||||
Preview = 2,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Folder:by_kind(kind)
|
function Folder:by_kind(kind)
|
||||||
if kind == self.Kind.Parent then
|
if kind == self.PARENT then
|
||||||
return cx.active.parent
|
return cx.active.parent
|
||||||
elseif kind == self.Kind.Current then
|
elseif kind == self.CURRENT then
|
||||||
return cx.active.current
|
return cx.active.current
|
||||||
elseif kind == self.Kind.Preview then
|
elseif kind == self.PREVIEW then
|
||||||
return cx.active.preview.folder
|
return cx.active.preview.folder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -23,14 +21,14 @@ function Folder:markers(area, markers)
|
||||||
|
|
||||||
local elements = {}
|
local elements = {}
|
||||||
local append = function(last)
|
local append = function(last)
|
||||||
local p = ui.Paragraph(
|
local p = ui.Bar(
|
||||||
ui.Rect {
|
ui.Rect {
|
||||||
x = math.max(1, area.x) - 1,
|
x = math.max(1, area.x) - 1,
|
||||||
y = area.y + last[1] - 1,
|
y = area.y + last[1] - 1,
|
||||||
w = 1,
|
w = 1,
|
||||||
h = 1 + last[2] - last[1],
|
h = 1 + last[2] - last[1],
|
||||||
},
|
},
|
||||||
{}
|
ui.Position.LEFT
|
||||||
)
|
)
|
||||||
|
|
||||||
if last[3] == 1 then
|
if last[3] == 1 then
|
||||||
|
|
@ -86,7 +84,7 @@ function Folder:highlighted_name(file)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Folder:parent(area)
|
function Folder:parent(area)
|
||||||
local folder = self:by_kind(self.Kind.Parent)
|
local folder = self:by_kind(self.PARENT)
|
||||||
if folder == nil then
|
if folder == nil then
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
@ -109,7 +107,7 @@ end
|
||||||
function Folder:current(area)
|
function Folder:current(area)
|
||||||
local markers = {}
|
local markers = {}
|
||||||
local items = {}
|
local items = {}
|
||||||
for i, f in ipairs(self:by_kind(self.Kind.Current).window) do
|
for i, f in ipairs(self:by_kind(self.CURRENT).window) do
|
||||||
local name = self:highlighted_name(f)
|
local name = self:highlighted_name(f)
|
||||||
|
|
||||||
-- Highlight hovered file
|
-- Highlight hovered file
|
||||||
|
|
@ -134,7 +132,7 @@ function Folder:current(area)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Folder:preview(area)
|
function Folder:preview(area)
|
||||||
local folder = self:by_kind(self.Kind.Preview)
|
local folder = self:by_kind(self.PREVIEW)
|
||||||
if folder == nil then
|
if folder == nil then
|
||||||
return {}
|
return {}
|
||||||
end
|
end
|
||||||
|
|
@ -154,11 +152,11 @@ function Folder:preview(area)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Folder:render(area, args)
|
function Folder:render(area, args)
|
||||||
if args.kind == self.Kind.Parent then
|
if args.kind == self.PARENT then
|
||||||
return self:parent(area)
|
return self:parent(area)
|
||||||
elseif args.kind == self.Kind.Current then
|
elseif args.kind == self.CURRENT then
|
||||||
return self:current(area)
|
return self:current(area)
|
||||||
elseif args.kind == self.Kind.Preview then
|
elseif args.kind == self.PREVIEW then
|
||||||
return self:preview(area)
|
return self:preview(area)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
25
plugin/preset/components/manager.lua
Normal file
25
plugin/preset/components/manager.lua
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
Manager = {}
|
||||||
|
|
||||||
|
function Manager:render(area)
|
||||||
|
local chunks = ui.Layout()
|
||||||
|
:direction(ui.Direction.HORIZONTAL)
|
||||||
|
:constraints({
|
||||||
|
ui.Constraint.Ratio(MANAGER.layout.parent, MANAGER.layout.all),
|
||||||
|
ui.Constraint.Ratio(MANAGER.layout.current, MANAGER.layout.all),
|
||||||
|
ui.Constraint.Ratio(MANAGER.layout.preview, MANAGER.layout.all),
|
||||||
|
})
|
||||||
|
:split(area)
|
||||||
|
|
||||||
|
return utils.flat {
|
||||||
|
-- Borders
|
||||||
|
ui.Bar(chunks[1], ui.Position.RIGHT):symbol(THEME.manager.border_symbol):style(THEME.manager.border_style),
|
||||||
|
ui.Bar(chunks[3], ui.Position.LEFT):symbol(THEME.manager.border_symbol):style(THEME.manager.border_style),
|
||||||
|
|
||||||
|
-- Parent
|
||||||
|
Folder:render(chunks[1]:padding(ui.Padding.x(1)), { kind = Folder.PARENT }),
|
||||||
|
-- Current
|
||||||
|
Folder:render(chunks[2], { kind = Folder.CURRENT }),
|
||||||
|
-- Preview
|
||||||
|
ui.Base(chunks[3]:padding(ui.Padding.x(1)), ui.Base.PREVIEW),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
@ -15,6 +15,22 @@ ui = {
|
||||||
BOTTOM = 3,
|
BOTTOM = 3,
|
||||||
LEFT = 4,
|
LEFT = 4,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Base = setmetatable({
|
||||||
|
PREVIEW = 0,
|
||||||
|
}, {
|
||||||
|
__call = function(_, ...) return ui.Base.new(...) end,
|
||||||
|
}),
|
||||||
|
Padding = setmetatable({
|
||||||
|
left = function(left) return ui.Padding.new(left, 0, 0, 0) end,
|
||||||
|
right = function(right) return ui.Padding.new(0, right, 0, 0) end,
|
||||||
|
top = function(top) return ui.Padding.new(0, 0, top, 0) end,
|
||||||
|
bottom = function(bottom) return ui.Padding.new(0, 0, 0, bottom) end,
|
||||||
|
x = function(x) return ui.Padding.new(x, x, 0, 0) end,
|
||||||
|
y = function(y) return ui.Padding.new(0, 0, y, y) end,
|
||||||
|
}, {
|
||||||
|
__call = function(_, ...) return ui.Padding.new(...) end,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
function ui.highlight_ranges(s, ranges)
|
function ui.highlight_ranges(s, ranges)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,19 @@
|
||||||
utils = utils or {}
|
utils = utils or {}
|
||||||
|
|
||||||
|
function utils.flat(t)
|
||||||
|
local r = {}
|
||||||
|
for _, v in ipairs(t) do
|
||||||
|
if type(v) == "table" then
|
||||||
|
for _, v2 in ipairs(utils.flat(v)) do
|
||||||
|
r[#r + 1] = v2
|
||||||
|
end
|
||||||
|
else
|
||||||
|
r[#r + 1] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
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)
|
function utils.readable_size(size)
|
||||||
|
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
use mlua::{AnyUserData, Table, TableExt};
|
|
||||||
|
|
||||||
use crate::{layout::{Bar, Gauge, List, Paragraph, Rect}, GLOBALS, LUA};
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn layout(values: Vec<AnyUserData>, buf: &mut ratatui::prelude::Buffer) -> mlua::Result<()> {
|
|
||||||
for value in values {
|
|
||||||
if let Ok(c) = value.take::<Paragraph>() {
|
|
||||||
c.render(buf)
|
|
||||||
} else if let Ok(c) = value.take::<List>() {
|
|
||||||
c.render(buf)
|
|
||||||
} else if let Ok(c) = value.take::<Bar>() {
|
|
||||||
c.render(buf)
|
|
||||||
} else if let Ok(c) = value.take::<Gauge>() {
|
|
||||||
c.render(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Status
|
|
||||||
pub struct Header;
|
|
||||||
|
|
||||||
impl Header {
|
|
||||||
pub fn render(
|
|
||||||
self,
|
|
||||||
area: ratatui::layout::Rect,
|
|
||||||
buf: &mut ratatui::prelude::Buffer,
|
|
||||||
) -> mlua::Result<()> {
|
|
||||||
let comp: Table = GLOBALS.get("Header")?;
|
|
||||||
let values: Vec<AnyUserData> = comp.call_method::<_, _>("render", Rect(area))?;
|
|
||||||
|
|
||||||
layout(values, buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Status
|
|
||||||
pub struct Status;
|
|
||||||
|
|
||||||
impl Status {
|
|
||||||
pub fn render(
|
|
||||||
self,
|
|
||||||
area: ratatui::layout::Rect,
|
|
||||||
buf: &mut ratatui::prelude::Buffer,
|
|
||||||
) -> mlua::Result<()> {
|
|
||||||
let comp: Table = GLOBALS.get("Status")?;
|
|
||||||
let values: Vec<AnyUserData> = comp.call_method::<_, _>("render", Rect(area))?;
|
|
||||||
|
|
||||||
layout(values, buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Folder
|
|
||||||
pub struct Folder {
|
|
||||||
pub kind: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Folder {
|
|
||||||
fn args(&self) -> mlua::Result<Table> {
|
|
||||||
let tbl = LUA.create_table()?;
|
|
||||||
tbl.set("kind", self.kind)?;
|
|
||||||
Ok(tbl)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(
|
|
||||||
self,
|
|
||||||
area: ratatui::layout::Rect,
|
|
||||||
buf: &mut ratatui::prelude::Buffer,
|
|
||||||
) -> mlua::Result<()> {
|
|
||||||
let comp: Table = GLOBALS.get("Folder")?;
|
|
||||||
let values: Vec<AnyUserData> =
|
|
||||||
comp.call_method::<_, _>("render", (Rect(area), self.args()?))?;
|
|
||||||
|
|
||||||
layout(values, buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
44
plugin/src/components/base.rs
Normal file
44
plugin/src/components/base.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
use mlua::{FromLua, Lua, Table, UserData, Value};
|
||||||
|
use ratatui::widgets::Widget;
|
||||||
|
|
||||||
|
use crate::{layout::Rect, GLOBALS, LUA};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Base {
|
||||||
|
area: ratatui::layout::Rect,
|
||||||
|
|
||||||
|
kind: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Base {
|
||||||
|
pub(crate) fn install() -> mlua::Result<()> {
|
||||||
|
let ui: Table = GLOBALS.get("ui")?;
|
||||||
|
let base: Table = ui.get("Base")?;
|
||||||
|
base.set(
|
||||||
|
"new",
|
||||||
|
LUA.create_function(|_, (area, kind): (Rect, u8)| Ok(Self { area: area.0, kind }))?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(self, cx: &core::Ctx, buf: &mut ratatui::buffer::Buffer) {
|
||||||
|
match self.kind {
|
||||||
|
0 => super::Preview::new(cx).render(self.area, buf),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> FromLua<'lua> for Base {
|
||||||
|
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> mlua::Result<Self> {
|
||||||
|
match value {
|
||||||
|
Value::UserData(ud) => Ok(ud.borrow::<Self>()?.clone()),
|
||||||
|
_ => Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: value.type_name(),
|
||||||
|
to: "Base",
|
||||||
|
message: Some("expected a Base".to_string()),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for Base {}
|
||||||
39
plugin/src/components/components.rs
Normal file
39
plugin/src/components/components.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
use mlua::{AnyUserData, Table};
|
||||||
|
use shared::RoCell;
|
||||||
|
|
||||||
|
use super::Base;
|
||||||
|
use crate::{layout::{Bar, Gauge, List, Paragraph}, GLOBALS};
|
||||||
|
|
||||||
|
pub(super) static COMP_FOLDER: RoCell<Table> = RoCell::new();
|
||||||
|
pub(super) static COMP_HEADER: RoCell<Table> = RoCell::new();
|
||||||
|
pub(super) static COMP_MANAGER: RoCell<Table> = RoCell::new();
|
||||||
|
pub(super) static COMP_STATUS: RoCell<Table> = RoCell::new();
|
||||||
|
|
||||||
|
pub fn init() -> mlua::Result<()> {
|
||||||
|
COMP_FOLDER.init(GLOBALS.get("Folder")?);
|
||||||
|
COMP_HEADER.init(GLOBALS.get("Header")?);
|
||||||
|
COMP_MANAGER.init(GLOBALS.get("Manager")?);
|
||||||
|
COMP_STATUS.init(GLOBALS.get("Status")?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn layout(
|
||||||
|
values: Vec<AnyUserData>,
|
||||||
|
cx: &core::Ctx,
|
||||||
|
buf: &mut ratatui::prelude::Buffer,
|
||||||
|
) -> mlua::Result<()> {
|
||||||
|
for value in values {
|
||||||
|
if let Ok(c) = value.take::<Paragraph>() {
|
||||||
|
c.render(buf)
|
||||||
|
} else if let Ok(c) = value.take::<List>() {
|
||||||
|
c.render(buf)
|
||||||
|
} else if let Ok(c) = value.take::<Bar>() {
|
||||||
|
c.render(buf)
|
||||||
|
} else if let Ok(c) = value.take::<Base>() {
|
||||||
|
c.render(cx, buf)
|
||||||
|
} else if let Ok(c) = value.take::<Gauge>() {
|
||||||
|
c.render(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
35
plugin/src/components/folder.rs
Normal file
35
plugin/src/components/folder.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
use mlua::TableExt;
|
||||||
|
use ratatui::widgets::Widget;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use super::{layout, COMP_FOLDER};
|
||||||
|
use crate::{layout::Rect, LUA};
|
||||||
|
|
||||||
|
pub struct Folder<'a> {
|
||||||
|
cx: &'a core::Ctx,
|
||||||
|
kind: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Folder<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn parent(cx: &'a core::Ctx) -> Self { Self { cx, kind: 0 } }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn current(cx: &'a core::Ctx) -> Self { Self { cx, kind: 1 } }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn preview(cx: &'a core::Ctx) -> Self { Self { cx, kind: 2 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Widget for Folder<'a> {
|
||||||
|
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) {
|
||||||
|
let mut f = || {
|
||||||
|
let args = LUA.create_table()?;
|
||||||
|
args.set("kind", self.kind)?;
|
||||||
|
layout(COMP_FOLDER.call_method::<_, _>("render", (Rect(area), args))?, self.cx, buf)
|
||||||
|
};
|
||||||
|
if let Err(e) = f() {
|
||||||
|
error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
plugin/src/components/header.rs
Normal file
24
plugin/src/components/header.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
use mlua::TableExt;
|
||||||
|
use ratatui::widgets::Widget;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use super::{layout, COMP_HEADER};
|
||||||
|
use crate::layout::Rect;
|
||||||
|
|
||||||
|
pub struct Header<'a> {
|
||||||
|
cx: &'a core::Ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Header<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(cx: &'a core::Ctx) -> Self { Self { cx } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Widget for Header<'a> {
|
||||||
|
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) {
|
||||||
|
let mut f = || layout(COMP_HEADER.call_method::<_, _>("render", Rect(area))?, self.cx, buf);
|
||||||
|
if let Err(e) = f() {
|
||||||
|
error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
plugin/src/components/manager.rs
Normal file
23
plugin/src/components/manager.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use mlua::TableExt;
|
||||||
|
use ratatui::widgets::Widget;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use super::{layout, COMP_MANAGER};
|
||||||
|
use crate::layout::Rect;
|
||||||
|
|
||||||
|
pub struct Manager<'a> {
|
||||||
|
cx: &'a core::Ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Manager<'a> {
|
||||||
|
pub fn new(cx: &'a core::Ctx) -> Self { Self { cx } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Widget for Manager<'a> {
|
||||||
|
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) {
|
||||||
|
let mut f = || layout(COMP_MANAGER.call_method::<_, _>("render", Rect(area))?, self.cx, buf);
|
||||||
|
if let Err(e) = f() {
|
||||||
|
error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
plugin/src/components/mod.rs
Normal file
17
plugin/src/components/mod.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#![allow(clippy::module_inception)]
|
||||||
|
|
||||||
|
mod base;
|
||||||
|
mod components;
|
||||||
|
mod folder;
|
||||||
|
mod header;
|
||||||
|
mod manager;
|
||||||
|
mod preview;
|
||||||
|
mod status;
|
||||||
|
|
||||||
|
pub use base::*;
|
||||||
|
pub use components::*;
|
||||||
|
pub use folder::*;
|
||||||
|
pub use header::*;
|
||||||
|
pub use manager::*;
|
||||||
|
use preview::*;
|
||||||
|
pub use status::*;
|
||||||
|
|
@ -27,7 +27,7 @@ impl<'a> Widget for Preview<'a> {
|
||||||
|
|
||||||
match &preview.lock.as_ref().unwrap().data {
|
match &preview.lock.as_ref().unwrap().data {
|
||||||
PreviewData::Folder => {
|
PreviewData::Folder => {
|
||||||
Folder::Preview.render(area, buf);
|
Folder::preview(self.cx).render(area, buf);
|
||||||
}
|
}
|
||||||
PreviewData::Text(s) => {
|
PreviewData::Text(s) => {
|
||||||
let p = Paragraph::new(s.as_bytes().into_text().unwrap());
|
let p = Paragraph::new(s.as_bytes().into_text().unwrap());
|
||||||
24
plugin/src/components/status.rs
Normal file
24
plugin/src/components/status.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
use mlua::TableExt;
|
||||||
|
use ratatui::widgets::Widget;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
|
use super::{layout, COMP_STATUS};
|
||||||
|
use crate::layout::Rect;
|
||||||
|
|
||||||
|
pub struct Status<'a> {
|
||||||
|
cx: &'a core::Ctx,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Status<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn new(cx: &'a core::Ctx) -> Self { Self { cx } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Widget for Status<'a> {
|
||||||
|
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) {
|
||||||
|
let mut f = || layout(COMP_STATUS.call_method::<_, _>("render", Rect(area))?, self.cx, buf);
|
||||||
|
if let Err(e) = f() {
|
||||||
|
error!("{:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,6 @@ use mlua::{AnyUserData, FromLua, Lua, Table, UserData, Value};
|
||||||
use super::{Rect, Style};
|
use super::{Rect, Style};
|
||||||
use crate::{GLOBALS, LUA};
|
use crate::{GLOBALS, LUA};
|
||||||
|
|
||||||
// --- Bar
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Bar {
|
pub struct Bar {
|
||||||
area: ratatui::layout::Rect,
|
area: ratatui::layout::Rect,
|
||||||
|
|
@ -36,23 +35,6 @@ impl Bar {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn new(area: ratatui::layout::Rect, position: ratatui::widgets::Borders) -> Self {
|
|
||||||
Self { area, position, symbol: Default::default(), style: Default::default() }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn symbol(mut self, symbol: &str) -> Self {
|
|
||||||
self.symbol = symbol.to_owned();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn style(mut self, style: ratatui::style::Style) -> Self {
|
|
||||||
self.style = Some(style);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(self, buf: &mut ratatui::buffer::Buffer) {
|
pub fn render(self, buf: &mut ratatui::buffer::Buffer) {
|
||||||
use ratatui::widgets::Borders;
|
use ratatui::widgets::Borders;
|
||||||
if self.area.area() == 0 {
|
if self.area.area() == 0 {
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,19 @@ mod gauge;
|
||||||
mod layout;
|
mod layout;
|
||||||
mod line;
|
mod line;
|
||||||
mod list;
|
mod list;
|
||||||
|
mod padding;
|
||||||
mod paragraph;
|
mod paragraph;
|
||||||
mod rect;
|
mod rect;
|
||||||
mod span;
|
mod span;
|
||||||
mod style;
|
mod style;
|
||||||
|
|
||||||
pub use bar::*;
|
pub(super) use bar::*;
|
||||||
pub(super) use constraint::*;
|
pub(super) use constraint::*;
|
||||||
pub(super) use gauge::*;
|
pub(super) use gauge::*;
|
||||||
pub(super) use layout::*;
|
pub(super) use layout::*;
|
||||||
pub(super) use line::*;
|
pub(super) use line::*;
|
||||||
pub(super) use list::*;
|
pub(super) use list::*;
|
||||||
|
pub(super) use padding::*;
|
||||||
pub(super) use paragraph::*;
|
pub(super) use paragraph::*;
|
||||||
pub(super) use rect::*;
|
pub(super) use rect::*;
|
||||||
pub(super) use span::*;
|
pub(super) use span::*;
|
||||||
|
|
|
||||||
41
plugin/src/layout/padding.rs
Normal file
41
plugin/src/layout/padding.rs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
use mlua::{FromLua, Lua, Table, UserData, Value};
|
||||||
|
|
||||||
|
use crate::{GLOBALS, LUA};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) struct Padding(pub(crate) ratatui::widgets::Padding);
|
||||||
|
|
||||||
|
impl Padding {
|
||||||
|
pub(crate) fn install() -> mlua::Result<()> {
|
||||||
|
let ui: Table = GLOBALS.get("ui")?;
|
||||||
|
let padding: Table = ui.get("Padding")?;
|
||||||
|
padding.set(
|
||||||
|
"new",
|
||||||
|
LUA.create_function(|_, args: (u16, u16, u16, u16)| {
|
||||||
|
Ok(Self(ratatui::widgets::Padding::new(args.0, args.1, args.2, args.3)))
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> FromLua<'lua> for Padding {
|
||||||
|
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> mlua::Result<Self> {
|
||||||
|
match value {
|
||||||
|
Value::UserData(ud) => Ok(*ud.borrow::<Self>()?),
|
||||||
|
_ => Err(mlua::Error::FromLuaConversionError {
|
||||||
|
from: value.type_name(),
|
||||||
|
to: "Padding",
|
||||||
|
message: Some("expected a Padding".to_string()),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData for Padding {
|
||||||
|
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use mlua::{FromLua, Lua, Table, UserData, Value};
|
use mlua::{FromLua, Lua, Table, UserData, Value};
|
||||||
|
|
||||||
|
use super::Padding;
|
||||||
use crate::{GLOBALS, LUA};
|
use crate::{GLOBALS, LUA};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
@ -47,4 +48,16 @@ impl UserData for Rect {
|
||||||
fields.add_field_method_get("top", |_, me| Ok(me.0.top()));
|
fields.add_field_method_get("top", |_, me| Ok(me.0.top()));
|
||||||
fields.add_field_method_get("bottom", |_, me| Ok(me.0.bottom()));
|
fields.add_field_method_get("bottom", |_, me| Ok(me.0.bottom()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
methods.add_method("padding", |_, me, padding: Padding| {
|
||||||
|
let mut r = me.0;
|
||||||
|
r.x = r.x.saturating_add(padding.0.left);
|
||||||
|
r.y = r.y.saturating_add(padding.0.top);
|
||||||
|
|
||||||
|
r.width = r.width.saturating_sub(padding.0.left + padding.0.right);
|
||||||
|
r.height = r.height.saturating_sub(padding.0.top + padding.0.bottom);
|
||||||
|
Ok(Self(r))
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
#![allow(clippy::unit_arg)]
|
#![allow(clippy::unit_arg)]
|
||||||
|
|
||||||
mod bindings;
|
mod bindings;
|
||||||
mod components;
|
pub mod components;
|
||||||
mod config;
|
mod config;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
mod plugin;
|
mod plugin;
|
||||||
mod scope;
|
mod scope;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use components::*;
|
|
||||||
use config::*;
|
use config::*;
|
||||||
pub use plugin::*;
|
pub use plugin::*;
|
||||||
pub use scope::*;
|
pub use scope::*;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use config::PLUGINS;
|
||||||
use mlua::{Lua, Table};
|
use mlua::{Lua, Table};
|
||||||
use shared::RoCell;
|
use shared::RoCell;
|
||||||
|
|
||||||
use crate::{bindings, layout, utils};
|
use crate::{bindings, components, layout, utils};
|
||||||
|
|
||||||
pub(crate) static LUA: RoCell<Lua> = RoCell::new();
|
pub(crate) static LUA: RoCell<Lua> = RoCell::new();
|
||||||
pub(crate) static GLOBALS: RoCell<Table> = RoCell::new();
|
pub(crate) static GLOBALS: RoCell<Table> = RoCell::new();
|
||||||
|
|
@ -20,6 +20,7 @@ pub fn init() {
|
||||||
// Components
|
// Components
|
||||||
lua.load(include_str!("../preset/components/folder.lua")).exec()?;
|
lua.load(include_str!("../preset/components/folder.lua")).exec()?;
|
||||||
lua.load(include_str!("../preset/components/header.lua")).exec()?;
|
lua.load(include_str!("../preset/components/header.lua")).exec()?;
|
||||||
|
lua.load(include_str!("../preset/components/manager.lua")).exec()?;
|
||||||
lua.load(include_str!("../preset/components/status.lua")).exec()?;
|
lua.load(include_str!("../preset/components/status.lua")).exec()?;
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
|
|
@ -27,10 +28,13 @@ pub fn init() {
|
||||||
GLOBALS.init(LUA.globals());
|
GLOBALS.init(LUA.globals());
|
||||||
utils::init()?;
|
utils::init()?;
|
||||||
bindings::init()?;
|
bindings::init()?;
|
||||||
|
components::init()?;
|
||||||
|
|
||||||
// Install
|
// Install
|
||||||
crate::Config.install()?;
|
crate::Config.install()?;
|
||||||
|
|
||||||
|
components::Base::install()?;
|
||||||
|
|
||||||
layout::Bar::install()?;
|
layout::Bar::install()?;
|
||||||
layout::Constraint::install()?;
|
layout::Constraint::install()?;
|
||||||
layout::Gauge::install()?;
|
layout::Gauge::install()?;
|
||||||
|
|
@ -38,6 +42,7 @@ pub fn init() {
|
||||||
layout::Line::install()?;
|
layout::Line::install()?;
|
||||||
layout::List::install()?;
|
layout::List::install()?;
|
||||||
layout::ListItem::install()?;
|
layout::ListItem::install()?;
|
||||||
|
layout::Padding::install()?;
|
||||||
layout::Paragraph::install()?;
|
layout::Paragraph::install()?;
|
||||||
layout::Rect::install()?;
|
layout::Rect::install()?;
|
||||||
layout::Span::install()?;
|
layout::Span::install()?;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue