mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
befcd555f9
commit
03b1e8728b
13 changed files with 409 additions and 156 deletions
86
Cargo.lock
generated
86
Cargo.lock
generated
|
|
@ -133,6 +133,7 @@ dependencies = [
|
|||
"crossterm",
|
||||
"futures",
|
||||
"libc",
|
||||
"plugin",
|
||||
"ratatui",
|
||||
"shared",
|
||||
"signal-hook-tokio",
|
||||
|
|
@ -217,6 +218,16 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.14.0"
|
||||
|
|
@ -544,6 +555,15 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "error-code"
|
||||
version = "2.3.1"
|
||||
|
|
@ -1073,6 +1093,33 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c3a7a7ff4481ec91b951a733390211a8ace1caba57266ccb5f4d4966704e560"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"erased-serde",
|
||||
"mlua-sys",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"serde-value",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mlua-sys"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ec8b54eddb76093069cce9eeffb4c7b3a1a0fe66962d7bd44c4867928149ca3"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
|
|
@ -1203,6 +1250,15 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "2.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
|
@ -1276,6 +1332,19 @@ dependencies = [
|
|||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plugin"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"config",
|
||||
"core",
|
||||
"mlua",
|
||||
"ratatui",
|
||||
"shared",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.10"
|
||||
|
|
@ -1450,6 +1519,12 @@ version = "0.1.23"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.14"
|
||||
|
|
@ -1492,6 +1567,16 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-value"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
||||
dependencies = [
|
||||
"ordered-float",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.188"
|
||||
|
|
@ -1542,7 +1627,6 @@ dependencies = [
|
|||
"libc",
|
||||
"parking_lot",
|
||||
"ratatui",
|
||||
"regex",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
use anyhow::Result;
|
||||
use config::theme::Color;
|
||||
use ratatui::{style::{Modifier, Style}, text::{Line, Span}, widgets::Paragraph};
|
||||
use ratatui::{prelude::{Buffer, Rect}, style::{Modifier, Style}, text::{Line, Span}, widgets::{Paragraph, Widget}};
|
||||
|
||||
pub struct Parser;
|
||||
|
||||
impl Parser {
|
||||
pub fn span(s: &str) -> Span<'static> {
|
||||
fn span(s: &str) -> Span<'static> {
|
||||
let Some((args, content)) = s.split_once(';') else {
|
||||
return Span::raw(s.to_string());
|
||||
};
|
||||
|
||||
let args = args.split(',').collect::<Vec<_>>();
|
||||
let args: Vec<_> = args.split(',').collect();
|
||||
if args.len() != 4 {
|
||||
return Span::raw(s.to_string());
|
||||
}
|
||||
|
|
@ -30,7 +31,7 @@ impl Parser {
|
|||
Span::styled(content.to_string(), style)
|
||||
}
|
||||
|
||||
pub fn line(s: &str) -> Line<'static> {
|
||||
fn line(s: &str) -> Line<'static> {
|
||||
let mut last = '\0';
|
||||
let mut spans: Vec<String> = vec![String::new()];
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ impl Parser {
|
|||
Line::from(spans.into_iter().map(|s| Self::span(&s)).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub fn paragraph(s: &str) -> Paragraph {
|
||||
fn paragraph(s: &str) -> Paragraph {
|
||||
let mut last = '\0';
|
||||
let mut lines: Vec<String> = vec![String::new()];
|
||||
|
||||
|
|
@ -68,22 +69,49 @@ impl Parser {
|
|||
Paragraph::new(lines.into_iter().map(|s| Self::line(&s)).collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
pub fn layout(s: &str) -> Paragraph {
|
||||
fn area(args: Vec<&str>) -> Result<Rect> {
|
||||
Ok(Rect {
|
||||
x: args[0].parse()?,
|
||||
y: args[1].parse()?,
|
||||
width: args[2].parse()?,
|
||||
height: args[3].parse()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn render(s: &str, buf: &mut Buffer) {
|
||||
let Some(s) = s.strip_prefix('R') else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut last = '\0';
|
||||
let mut lines: Vec<String> = vec![String::new()];
|
||||
let mut paragraphs: Vec<String> = vec![String::new()];
|
||||
|
||||
for c in s.chars() {
|
||||
if c == '\0' && last == '\\' {
|
||||
let last = lines.last_mut().unwrap();
|
||||
let last = paragraphs.last_mut().unwrap();
|
||||
last.pop();
|
||||
last.push(c);
|
||||
} else if c == '\0' {
|
||||
lines.push(String::new());
|
||||
paragraphs.push(String::new());
|
||||
} else {
|
||||
lines.last_mut().unwrap().push(c);
|
||||
paragraphs.last_mut().unwrap().push(c);
|
||||
}
|
||||
last = c;
|
||||
}
|
||||
Paragraph::new(lines.into_iter().map(|s| Self::line(&s)).collect::<Vec<_>>())
|
||||
|
||||
for paragraph in paragraphs {
|
||||
let Some((args, content)) = paragraph.split_once(';') else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let args: Vec<_> = args.split(',').collect();
|
||||
if args.len() != 4 {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok(area) = Self::area(args) {
|
||||
Self::paragraph(content).render(area, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use core::Ctx;
|
||||
|
||||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, text::Line, widgets::{Paragraph, Widget}};
|
||||
use ratatui::{buffer::Buffer, layout::{self, Constraint, Direction, Rect}, widgets::Widget};
|
||||
use tracing::info;
|
||||
|
||||
use crate::Parser;
|
||||
use crate::parser::Parser;
|
||||
|
||||
pub(crate) struct Layout<'a> {
|
||||
cx: &'a Ctx,
|
||||
|
|
@ -20,63 +20,14 @@ impl<'a> Widget for Layout<'a> {
|
|||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||
.split(area);
|
||||
|
||||
// Left::new(self.cx).render(chunks[0], buf);
|
||||
// Right::new(self.cx).render(chunks[1], buf);
|
||||
|
||||
let mut spans = vec![];
|
||||
if let Ok(mode) = plugin::Status::mode(self.cx) {
|
||||
spans.extend(Parser::line(&mode).spans);
|
||||
}
|
||||
|
||||
let x = plugin::Status::size(self.cx);
|
||||
let x = plugin::Status::layout(self.cx, area);
|
||||
if x.is_err() {
|
||||
info!("Error: {:?}", x);
|
||||
info!("{:?}", x);
|
||||
return;
|
||||
}
|
||||
if let Ok(size) = x {
|
||||
spans.extend(Parser::line(&size).spans);
|
||||
}
|
||||
|
||||
let x = plugin::Status::name(self.cx);
|
||||
if x.is_err() {
|
||||
info!("Error: {:?}", x);
|
||||
return;
|
||||
}
|
||||
if let Ok(name) = x {
|
||||
spans.extend(Parser::line(&name).spans);
|
||||
}
|
||||
|
||||
Paragraph::new(Line::from(spans)).render(chunks[0], buf);
|
||||
|
||||
// Right
|
||||
let mut spans = vec![];
|
||||
|
||||
let x = plugin::Status::permissions(self.cx);
|
||||
if x.is_err() {
|
||||
info!("Error: {:?}", x);
|
||||
return;
|
||||
}
|
||||
if let Ok(name) = x {
|
||||
spans.extend(Parser::line(&name).spans);
|
||||
}
|
||||
|
||||
let x = plugin::Status::percentage(self.cx);
|
||||
if x.is_err() {
|
||||
info!("Error: {:?}", x);
|
||||
return;
|
||||
}
|
||||
if let Ok(name) = x {
|
||||
spans.extend(Parser::line(&name).spans);
|
||||
}
|
||||
|
||||
let x = plugin::Status::position(self.cx);
|
||||
if x.is_err() {
|
||||
info!("Error: {:?}", x);
|
||||
return;
|
||||
}
|
||||
if let Ok(name) = x {
|
||||
spans.extend(Parser::line(&name).spans);
|
||||
}
|
||||
Paragraph::new(Line::from(spans)).render(chunks[1], buf);
|
||||
if let Ok(s) = x {
|
||||
Parser::render(&s, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"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","Mintty","nixos","nixpkgs","SIGTSTP","SIGCONT","SIGCONT","backstack","natsort","natsort","USERPROFILE"],"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"],"language":"en","version":"0.2"}
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ shared = { path = "../shared" }
|
|||
anyhow = "^1"
|
||||
mlua = { version = "^0", features = [ "lua54", "serialize" ] }
|
||||
tracing = "^0"
|
||||
ratatui = "^0"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,15 @@
|
|||
function layout() end
|
||||
function layout(area)
|
||||
local chunks = yazi
|
||||
.Layout()
|
||||
:direction(false)
|
||||
:constraints({ yazi.Constraint.Percentage(50), yazi.Constraint.Percentage(50) })
|
||||
:split(area)
|
||||
|
||||
return yazi.Paragraph.render(
|
||||
yazi.Paragraph(mode(), size(), name()):area(chunks[1]),
|
||||
yazi.Paragraph(permissions(), percentage(), position()):area(chunks[2])
|
||||
)
|
||||
end
|
||||
|
||||
function mode()
|
||||
local mode = cx.manager.mode:upper()
|
||||
|
|
@ -6,45 +17,41 @@ function mode()
|
|||
mode = "UN-SET"
|
||||
end
|
||||
|
||||
return yazi
|
||||
.Line(
|
||||
return yazi.Line(
|
||||
yazi.Span(THEME.status.separator.opening):fg(THEME.status.mode_normal.bg),
|
||||
yazi.Span(" " .. mode .. " "):style(THEME.status.mode_normal)
|
||||
)
|
||||
:to_string()
|
||||
end
|
||||
|
||||
function size()
|
||||
local hovered = cx.manager.current_hovered
|
||||
if hovered == nil then
|
||||
return ""
|
||||
return yazi.Span("")
|
||||
end
|
||||
|
||||
return yazi
|
||||
.Line(
|
||||
return yazi.Line(
|
||||
yazi.Span(" " .. hovered.length .. " "):fg(THEME.status.mode_normal.bg):bg(THEME.status.fancy.bg),
|
||||
yazi.Span(THEME.status.separator.closing):fg(THEME.status.fancy.bg)
|
||||
)
|
||||
:to_string()
|
||||
end
|
||||
|
||||
function name()
|
||||
local hovered = cx.manager.current_hovered
|
||||
if hovered == nil then
|
||||
return ""
|
||||
return yazi.Span("")
|
||||
end
|
||||
|
||||
return yazi.Span(" " .. utils.basename(hovered.url)):to_string()
|
||||
return yazi.Span(" " .. utils.basename(hovered.url))
|
||||
end
|
||||
|
||||
function permissions()
|
||||
local hovered = cx.manager.current_hovered
|
||||
if hovered == nil then
|
||||
return ""
|
||||
return yazi.Span("")
|
||||
end
|
||||
|
||||
if hovered.permissions == nil then
|
||||
return ""
|
||||
return yazi.Span("")
|
||||
end
|
||||
|
||||
local spans = {}
|
||||
|
|
@ -60,7 +67,7 @@ function permissions()
|
|||
end
|
||||
spans[i] = yazi.Span(c):style(style)
|
||||
end
|
||||
return yazi.Line:from(spans):to_string()
|
||||
return yazi.Line:from(spans)
|
||||
end
|
||||
|
||||
function percentage()
|
||||
|
|
@ -77,16 +84,14 @@ function percentage()
|
|||
percent = string.format(" %3d%% ", percent)
|
||||
end
|
||||
|
||||
return yazi
|
||||
.Line(
|
||||
return yazi.Line(
|
||||
yazi.Span(THEME.status.separator.opening):fg(THEME.status.fancy.bg),
|
||||
yazi.Span(percent):fg(THEME.status.mode_normal.bg):bg(THEME.status.fancy.bg)
|
||||
)
|
||||
:to_string()
|
||||
end
|
||||
|
||||
function position()
|
||||
local cursor = cx.manager.current_cursor
|
||||
local length = cx.manager.current_length
|
||||
return string.format(" %d/%d ", cursor + 1, length)
|
||||
return yazi.Span(string.format(" %d/%d ", cursor + 1, length))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ local Paragraph = {}
|
|||
|
||||
function Paragraph:new(...)
|
||||
local o = {
|
||||
position = nil,
|
||||
lines = { ... },
|
||||
}
|
||||
setmetatable(o, self)
|
||||
|
|
@ -11,6 +12,11 @@ end
|
|||
|
||||
function Paragraph:from(lines) return self:new(table.unpack(lines)) end
|
||||
|
||||
function Paragraph:area(rect)
|
||||
self.position = rect
|
||||
return self
|
||||
end
|
||||
|
||||
function Paragraph:to_string()
|
||||
local s = ""
|
||||
for _, line in ipairs(self.lines) do
|
||||
|
|
@ -19,6 +25,26 @@ function Paragraph:to_string()
|
|||
return s.sub(s, 1, -2)
|
||||
end
|
||||
|
||||
function Paragraph:aaa() return self:to_string() end
|
||||
|
||||
function Paragraph.render(...)
|
||||
local s = "R"
|
||||
for _, paragraph in ipairs { ... } do
|
||||
s = s
|
||||
.. paragraph.position.x
|
||||
.. ","
|
||||
.. paragraph.position.y
|
||||
.. ","
|
||||
.. paragraph.position.width
|
||||
.. ","
|
||||
.. paragraph.position.height
|
||||
.. ";"
|
||||
.. paragraph:to_string():gsub("\0", "\\\0")
|
||||
.. "\0"
|
||||
end
|
||||
return s.sub(s, 1, -2)
|
||||
end
|
||||
|
||||
setmetatable(Paragraph, {
|
||||
__call = function(self, ...) return self:new(...) end,
|
||||
__tostring = function(self) return self:to_string() end,
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ impl<'a> Manager<'a> {
|
|||
|
||||
impl<'a> UserData for Manager<'a> {
|
||||
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("mode", |_, this| Ok(this.0.active().mode().to_string()));
|
||||
fields.add_field_method_get("mode", |_, me| Ok(me.0.active().mode().to_string()));
|
||||
|
||||
fields.add_field_method_get("current_cursor", |_, this| Ok(this.0.current().cursor()));
|
||||
fields.add_field_method_get("current_length", |_, this| Ok(this.0.current().files.len()));
|
||||
fields.add_field_method_get("current_hovered", |_, this| {
|
||||
Ok(this.0.current().hovered.as_ref().map(File::from))
|
||||
fields.add_field_method_get("current_cursor", |_, me| Ok(me.0.current().cursor()));
|
||||
fields.add_field_method_get("current_length", |_, me| Ok(me.0.current().files.len()));
|
||||
fields.add_field_method_get("current_hovered", |_, me| {
|
||||
Ok(me.0.current().hovered.as_ref().map(File::from))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ impl<'a> Tasks<'a> {
|
|||
|
||||
impl<'a> UserData for Tasks<'a> {
|
||||
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("progress", |lua, this| lua.to_value(&this.0.progress))
|
||||
fields.add_field_method_get("progress", |lua, me| lua.to_value(&me.0.progress))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -44,17 +44,17 @@ impl From<&core::files::File> for File {
|
|||
|
||||
impl UserData for File {
|
||||
fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("url", |_, this| Ok(this.0.url().to_string_lossy().to_string()));
|
||||
fields.add_field_method_get("length", |_, this| Ok(this.0.length()));
|
||||
fields.add_field_method_get("link_to", |_, this| {
|
||||
Ok(this.0.link_to().map(|l| l.to_string_lossy().to_string()))
|
||||
fields.add_field_method_get("url", |_, me| Ok(me.0.url().to_string_lossy().to_string()));
|
||||
fields.add_field_method_get("length", |_, me| Ok(me.0.length()));
|
||||
fields.add_field_method_get("link_to", |_, me| {
|
||||
Ok(me.0.link_to().map(|l| l.to_string_lossy().to_string()))
|
||||
});
|
||||
fields.add_field_method_get("is_link", |_, this| Ok(this.0.is_link()));
|
||||
fields.add_field_method_get("is_hidden", |_, this| Ok(this.0.is_hidden()));
|
||||
fields.add_field_method_get("is_link", |_, me| Ok(me.0.is_link()));
|
||||
fields.add_field_method_get("is_hidden", |_, me| Ok(me.0.is_hidden()));
|
||||
|
||||
// Meta
|
||||
fields.add_field_method_get("permissions", |_, this| {
|
||||
Ok(shared::permissions(this.0.meta().permissions()))
|
||||
fields.add_field_method_get("permissions", |_, me| {
|
||||
Ok(shared::permissions(me.0.meta().permissions()))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
178
plugin/src/layout.rs
Normal file
178
plugin/src/layout.rs
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
use mlua::{AnyUserData, FromLua, Lua, Table, UserData, UserDataMethods, Value};
|
||||
use ratatui::layout;
|
||||
|
||||
use crate::LUA;
|
||||
|
||||
// --- Rect
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Rect(layout::Rect);
|
||||
|
||||
impl From<layout::Rect> for Rect {
|
||||
fn from(value: layout::Rect) -> Self { Self(value) }
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Rect {
|
||||
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: "Rect",
|
||||
message: Some("expected a Rect".to_string()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
// --- Constraint
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Constraint(layout::Constraint);
|
||||
|
||||
impl Constraint {
|
||||
pub(super) fn install() -> mlua::Result<()> {
|
||||
let globals = LUA.globals();
|
||||
let yazi = globals.get::<_, Table>("yazi")?;
|
||||
|
||||
let constraint = LUA.create_table()?;
|
||||
constraint.set(
|
||||
"Percentage",
|
||||
LUA.create_function(|_, n: u16| Ok(Constraint(layout::Constraint::Percentage(n))))?,
|
||||
)?;
|
||||
constraint.set(
|
||||
"Ratio",
|
||||
LUA
|
||||
.create_function(|_, (a, b): (u32, u32)| Ok(Constraint(layout::Constraint::Ratio(a, b))))?,
|
||||
)?;
|
||||
constraint.set(
|
||||
"Length",
|
||||
LUA.create_function(|_, n: u16| Ok(Constraint(layout::Constraint::Length(n))))?,
|
||||
)?;
|
||||
constraint
|
||||
.set("Max", LUA.create_function(|_, n: u16| Ok(Constraint(layout::Constraint::Max(n))))?)?;
|
||||
constraint
|
||||
.set("Min", LUA.create_function(|_, n: u16| Ok(Constraint(layout::Constraint::Min(n))))?)?;
|
||||
|
||||
yazi.set("Constraint", constraint)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Constraint {
|
||||
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: "Constraint",
|
||||
message: Some("expected a Constraint".to_string()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Constraint {}
|
||||
|
||||
// --- Layout
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Layout {
|
||||
direction: bool,
|
||||
margin: Option<layout::Margin>,
|
||||
constraints: Vec<layout::Constraint>,
|
||||
}
|
||||
|
||||
impl Layout {
|
||||
pub(super) fn install() -> mlua::Result<()> {
|
||||
let globals = LUA.globals();
|
||||
|
||||
let yazi = globals.get::<_, Table>("yazi")?;
|
||||
yazi.set("Layout", LUA.create_function(|_, ()| Ok(Self::default()))?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Layout {
|
||||
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: "Layout",
|
||||
message: Some("expected a Layout".to_string()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for Layout {
|
||||
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_function("direction", |_, (ud, value): (AnyUserData, bool)| {
|
||||
{
|
||||
let mut me = ud.borrow_mut::<Self>()?;
|
||||
me.direction = value;
|
||||
}
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("margin", |_, (ud, value): (AnyUserData, u16)| {
|
||||
{
|
||||
let mut me = ud.borrow_mut::<Self>()?;
|
||||
me.margin = Some(layout::Margin::new(value, value));
|
||||
}
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("margin_h", |_, (ud, value): (AnyUserData, u16)| {
|
||||
{
|
||||
let mut me = ud.borrow_mut::<Self>()?;
|
||||
if let Some(margin) = &mut me.margin {
|
||||
margin.horizontal = value;
|
||||
} else {
|
||||
me.margin = Some(layout::Margin::new(value, 0));
|
||||
}
|
||||
}
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("margin_v", |_, (ud, value): (AnyUserData, u16)| {
|
||||
{
|
||||
let mut me = ud.borrow_mut::<Self>()?;
|
||||
if let Some(margin) = &mut me.margin {
|
||||
margin.vertical = value;
|
||||
} else {
|
||||
me.margin = Some(layout::Margin::new(0, value));
|
||||
}
|
||||
}
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("constraints", |_, (ud, value): (AnyUserData, Vec<Constraint>)| {
|
||||
{
|
||||
let mut me = ud.borrow_mut::<Self>()?;
|
||||
me.constraints = value.into_iter().map(|c| c.0).collect();
|
||||
}
|
||||
Ok(ud)
|
||||
});
|
||||
methods.add_function("split", |_, (ud, value): (AnyUserData, Rect)| {
|
||||
let me = ud.borrow::<Self>()?;
|
||||
|
||||
let mut layout = layout::Layout::new()
|
||||
.direction(if me.direction {
|
||||
layout::Direction::Horizontal
|
||||
} else {
|
||||
layout::Direction::Vertical
|
||||
})
|
||||
.constraints(me.constraints.as_slice());
|
||||
|
||||
if let Some(margin) = me.margin {
|
||||
layout = layout.horizontal_margin(margin.horizontal);
|
||||
layout = layout.vertical_margin(margin.vertical);
|
||||
}
|
||||
|
||||
let chunks: Vec<Rect> = layout.split(value.0).iter().copied().map(Rect).collect();
|
||||
Ok(chunks)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
#![allow(clippy::unit_arg)]
|
||||
|
||||
mod bindings;
|
||||
mod layout;
|
||||
mod plugin;
|
||||
mod status;
|
||||
|
||||
pub use bindings::*;
|
||||
pub use layout::*;
|
||||
pub use plugin::*;
|
||||
pub use status::*;
|
||||
|
|
|
|||
|
|
@ -3,21 +3,34 @@ use config::THEME;
|
|||
use mlua::{Lua, LuaSerdeExt};
|
||||
use shared::RoCell;
|
||||
|
||||
use crate::layout;
|
||||
|
||||
pub(crate) static LUA: RoCell<Lua> = RoCell::new();
|
||||
|
||||
pub fn init() {
|
||||
fn inner() -> Result<()> {
|
||||
let lua = Lua::new();
|
||||
|
||||
// Base
|
||||
lua.load(include_str!("../preset/utils.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/inspect/inspect.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/span.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/line.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/paragraph.lua")).exec()?;
|
||||
|
||||
lua.load(include_str!("../preset/status.lua")).exec()?;
|
||||
// Elements
|
||||
lua.load(include_str!("../preset/elements/span.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/elements/line.lua")).exec()?;
|
||||
lua.load(include_str!("../preset/elements/paragraph.lua")).exec()?;
|
||||
|
||||
// Components
|
||||
lua.load(include_str!("../preset/components/status.lua")).exec()?;
|
||||
|
||||
// Initialize
|
||||
lua.globals().set("THEME", lua.to_value(&*THEME)?)?;
|
||||
Ok(LUA.init(lua))
|
||||
LUA.init(lua);
|
||||
|
||||
layout::Layout::install()?;
|
||||
layout::Constraint::install()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
inner().expect("failed to initialize Lua");
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
use core::Ctx;
|
||||
|
||||
use mlua::{Function, Result};
|
||||
use ratatui::layout;
|
||||
|
||||
use crate::{bindings, LUA};
|
||||
use crate::{bindings, Rect, LUA};
|
||||
|
||||
pub struct Status;
|
||||
|
||||
impl Status {
|
||||
fn scoped<T, F: FnOnce() -> Result<T>>(cx: &Ctx, f: F) -> Result<T> {
|
||||
fn scope<T, F: FnOnce() -> Result<T>>(cx: &Ctx, f: F) -> Result<T> {
|
||||
LUA.scope(|scope| {
|
||||
let manager = scope.create_nonstatic_userdata(bindings::Manager::new(&cx.manager))?;
|
||||
let tasks = scope.create_nonstatic_userdata(bindings::Tasks::new(&cx.tasks))?;
|
||||
|
|
@ -21,45 +22,10 @@ impl Status {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn mode(cx: &Ctx) -> Result<String> {
|
||||
Self::scoped(cx, || {
|
||||
let mode: Function = LUA.globals().get("mode")?;
|
||||
mode.call::<_, String>(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn size(cx: &Ctx) -> Result<String> {
|
||||
Self::scoped(cx, || {
|
||||
let size: Function = LUA.globals().get("size")?;
|
||||
size.call::<_, String>(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn name(cx: &Ctx) -> Result<String> {
|
||||
Self::scoped(cx, || {
|
||||
let size: Function = LUA.globals().get("name")?;
|
||||
size.call::<_, String>(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn permissions(cx: &Ctx) -> Result<String> {
|
||||
Self::scoped(cx, || {
|
||||
let size: Function = LUA.globals().get("permissions")?;
|
||||
size.call::<_, String>(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn percentage(cx: &Ctx) -> Result<String> {
|
||||
Self::scoped(cx, || {
|
||||
let size: Function = LUA.globals().get("percentage")?;
|
||||
size.call::<_, String>(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn position(cx: &Ctx) -> Result<String> {
|
||||
Self::scoped(cx, || {
|
||||
let size: Function = LUA.globals().get("position")?;
|
||||
size.call::<_, String>(())
|
||||
pub fn layout(cx: &Ctx, area: layout::Rect) -> Result<String> {
|
||||
Self::scope(cx, || {
|
||||
let layout: Function = LUA.globals().get("layout")?;
|
||||
layout.call::<_, String>(Rect::from(area))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,5 @@ crossterm = "^0"
|
|||
futures = "^0"
|
||||
libc = "^0"
|
||||
parking_lot = "^0"
|
||||
ratatui = { version = "^0" }
|
||||
regex = "^1"
|
||||
ratatui = "^0"
|
||||
tokio = { version = "^1", features = [ "parking_lot", "macros", "rt-multi-thread", "sync", "time", "fs" ] }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue