From 61c633ec442efec5e417dca5588a1fdb2f7ee550 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Thu, 5 Oct 2023 18:20:35 +0800 Subject: [PATCH] .. --- app/src/executor.rs | 2 +- app/src/header/layout.rs | 2 +- app/src/help/layout.rs | 2 +- app/src/manager/folder.rs | 28 ++------- app/src/manager/layout.rs | 17 +++--- app/src/manager/preview.rs | 2 +- app/src/root.rs | 4 +- app/src/status/layout.rs | 12 +--- app/src/tasks/layout.rs | 32 ++++------ app/src/which/layout.rs | 4 +- config/preset/theme.toml | 7 ++- config/src/theme/list.rs | 7 ++- config/src/theme/theme.rs | 4 +- core/src/manager/tab.rs | 19 +++--- cspell.json | 2 +- plugin/Cargo.toml | 2 +- plugin/preset/components/folder.lua | 55 +++++++++++++---- plugin/preset/components/status.lua | 20 +++---- plugin/src/bindings/bindings.rs | 2 +- plugin/src/bindings/mod.rs | 4 +- plugin/src/bindings/{manager.rs => tab.rs} | 68 +++++++++++++++++----- plugin/src/layout/line.rs | 2 +- plugin/src/layout/paragraph.rs | 12 +++- plugin/src/layout/style.rs | 2 - plugin/src/scope.rs | 2 +- shared/src/fs.rs | 1 - 26 files changed, 175 insertions(+), 139 deletions(-) rename plugin/src/bindings/{manager.rs => tab.rs} (78%) diff --git a/app/src/executor.rs b/app/src/executor.rs index 71810de4c..783ba1e4d 100644 --- a/app/src/executor.rs +++ b/app/src/executor.rs @@ -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}; diff --git a/app/src/header/layout.rs b/app/src/header/layout.rs index 292a3c6e3..4755b9bd9 100644 --- a/app/src/header/layout.rs +++ b/app/src/header/layout.rs @@ -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; diff --git a/app/src/help/layout.rs b/app/src/help/layout.rs index fc4f90257..d12acdb82 100644 --- a/app/src/help/layout.rs +++ b/app/src/help/layout.rs @@ -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); diff --git a/app/src/manager/folder.rs b/app/src/manager/folder.rs index bee1fbab3..aba92a69e 100644 --- a/app/src/manager/folder.rs +++ b/app/src/manager/folder.rs @@ -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 { // 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()) diff --git a/app/src/manager/layout.rs b/app/src/manager/layout.rs index f3f8ba183..f0e659ff7 100644 --- a/app/src/manager/layout.rs +++ b/app/src/manager/layout.rs @@ -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)); diff --git a/app/src/manager/preview.rs b/app/src/manager/preview.rs index ca58e19e6..455d1ca8a 100644 --- a/app/src/manager/preview.rs +++ b/app/src/manager/preview.rs @@ -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()); diff --git a/app/src/root.rs b/app/src/root.rs index 8ce31b97f..fa7d348f2 100644 --- a/app/src/root.rs +++ b/app/src/root.rs @@ -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); diff --git a/app/src/status/layout.rs b/app/src/status/layout.rs index c6d42c9e4..d6ecd6103 100644 --- a/app/src/status/layout.rs +++ b/app/src/status/layout.rs @@ -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, -} - -impl<'a> Layout<'a> { - pub(crate) fn new(cx: &'a Ctx) -> Self { Self { cx } } -} +pub(crate) struct Layout; -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() { diff --git a/app/src/tasks/layout.rs b/app/src/tasks/layout.rs index 14b1bd64b..099057fc1 100644 --- a/app/src/tasks/layout.rs +++ b/app/src/tasks/layout.rs @@ -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] } } diff --git a/app/src/which/layout.rs b/app/src/which/layout.rs index ddbff14b8..686bf8be2 100644 --- a/app/src/which/layout.rs +++ b/app/src/which/layout.rs @@ -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); diff --git a/config/preset/theme.toml b/config/preset/theme.toml index dec410e42..25fcfa7f0 100644 --- a/config/preset/theme.toml +++ b/config/preset/theme.toml @@ -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 } diff --git a/config/src/theme/list.rs b/config/src/theme/list.rs index 7db9415d5..5ce1556bd 100644 --- a/config/src/theme/list.rs +++ b/config/src/theme/list.rs @@ -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, } diff --git a/config/src/theme/theme.rs b/config/src/theme/theme.rs index af73fab72..5b324e729 100644 --- a/config/src/theme/theme.rs +++ b/config/src/theme/theme.rs @@ -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)] diff --git a/core/src/manager/tab.rs b/core/src/manager/tab.rs index dbcada643..64be01178 100644 --- a/core/src/manager/tab.rs +++ b/core/src/manager/tab.rs @@ -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, + pub mode: Mode, + pub current: Folder, + pub parent: Option, pub(super) backstack: Backstack, pub(super) history: BTreeMap, @@ -453,14 +453,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 @@ -473,10 +469,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 { diff --git a/cspell.json b/cspell.json index d9bb06625..4c8f6379b 100644 --- a/cspell.json +++ b/cspell.json @@ -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"} diff --git a/plugin/Cargo.toml b/plugin/Cargo.toml index 147bf0ff6..1cfca9ff4 100644 --- a/plugin/Cargo.toml +++ b/plugin/Cargo.toml @@ -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" diff --git a/plugin/preset/components/folder.lua b/plugin/preset/components/folder.lua index 62537d50b..1f432272c 100644 --- a/plugin/preset/components/folder.lua +++ b/plugin/preset/components/folder.lua @@ -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) diff --git a/plugin/preset/components/status.lua b/plugin/preset/components/status.lua index eb5716185..b4de3af3f 100644 --- a/plugin/preset/components/status.lua +++ b/plugin/preset/components/status.lua @@ -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 { diff --git a/plugin/src/bindings/bindings.rs b/plugin/src/bindings/bindings.rs index 363945fc8..71d40d38a 100644 --- a/plugin/src/bindings/bindings.rs +++ b/plugin/src/bindings/bindings.rs @@ -1,5 +1,5 @@ pub fn init() -> mlua::Result<()> { - super::manager::Manager::init()?; + super::tab::Tab::init()?; super::tasks::Tasks::init()?; Ok(()) diff --git a/plugin/src/bindings/mod.rs b/plugin/src/bindings/mod.rs index 72377fbb3..2befe99a5 100644 --- a/plugin/src/bindings/mod.rs +++ b/plugin/src/bindings/mod.rs @@ -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::*; diff --git a/plugin/src/bindings/manager.rs b/plugin/src/bindings/tab.rs similarity index 78% rename from plugin/src/bindings/manager.rs rename to plugin/src/bindings/tab.rs index 123d52c09..c873ec0ab 100644 --- a/plugin/src/bindings/manager.rs +++ b/plugin/src/bindings/tab.rs @@ -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::(|reg| { + LUA.register_userdata_type::(|reg| { reg.add_field_function_get("mode", |_, me| me.named_user_value::("mode")); reg.add_field_function_get("parent", |_, me| me.named_user_value::("parent")); reg.add_field_function_get("current", |_, me| me.named_user_value::("current")); @@ -85,6 +89,9 @@ impl<'a, 'b> Manager<'a, 'b> { reg.add_function("style", |_, me: AnyUserData| { me.named_user_value::("style")?.call::<_, Style>(()) }); + reg.add_function("selected", |_, me: AnyUserData| { + me.named_user_value::("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> { 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::>(), )?; 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> { + fn file( + &self, + idx: usize, + inner: &'a core::files::File, + folder: &'a core::manager::Folder, + ) -> mlua::Result> { 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) } diff --git a/plugin/src/layout/line.rs b/plugin/src/layout/line.rs index 4b04b6ccb..52de8ffac 100644 --- a/plugin/src/layout/line.rs +++ b/plugin/src/layout/line.rs @@ -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::