mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
..
This commit is contained in:
parent
a3971fc4f5
commit
46c54f6bad
26 changed files with 175 additions and 139 deletions
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
pub fn init() -> mlua::Result<()> {
|
||||
super::manager::Manager::init()?;
|
||||
super::tab::Tab::init()?;
|
||||
super::tasks::Tasks::init()?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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)| {
|
||||
|
|
|
|||
|
|
@ -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)| {
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue