From bed8172347c1b08f51d7d5c8eae9135f1057cff3 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Fri, 20 Oct 2023 09:10:07 +0800 Subject: [PATCH] refactor: tab-specific config --- app/src/app.rs | 4 +- app/src/executor.rs | 20 ++-------- config/preset/yazi.toml | 1 + config/src/manager/linemode.rs | 26 +++++++++++++ config/src/manager/manager.rs | 3 +- config/src/manager/mod.rs | 2 + config/src/manager/sorting.rs | 18 +++++++-- config/src/theme/color.rs | 2 +- core/src/files/sorter.rs | 20 +++------- core/src/manager/commands/peek.rs | 4 +- core/src/manager/tabs.rs | 6 +-- core/src/tab/commands/escape.rs | 12 +++--- core/src/tab/commands/hidden.rs | 18 +++++++++ core/src/tab/commands/mod.rs | 2 + core/src/tab/commands/search.rs | 4 +- core/src/tab/commands/sort.rs | 18 +++++++++ core/src/tab/config.rs | 50 +++++++++++++++++++++++++ core/src/tab/mod.rs | 2 + core/src/tab/tab.rs | 62 +++++++------------------------ cspell.json | 2 +- plugin/src/components/base.rs | 5 +-- 21 files changed, 177 insertions(+), 104 deletions(-) create mode 100644 config/src/manager/linemode.rs create mode 100644 core/src/tab/commands/hidden.rs create mode 100644 core/src/tab/commands/sort.rs create mode 100644 core/src/tab/config.rs diff --git a/app/src/app.rs b/app/src/app.rs index dbcb1520..059f5ca2 100644 --- a/app/src/app.rs +++ b/app/src/app.rs @@ -89,13 +89,13 @@ impl App { fn dispatch_resize(&mut self) { self.cx.manager.current_mut().set_page(true); - self.cx.manager.active_mut().preview_reset(); + self.cx.manager.active_mut().preview.reset(|_| true); self.cx.manager.peek(true, self.cx.image_layer()); emit!(Render); } fn dispatch_stop(&mut self, state: bool, tx: Option>) { - self.cx.manager.active_mut().preview_reset_image(); + self.cx.manager.active_mut().preview.reset(|l| l.is_image()); if state { self.signals.stop_term(true); self.term = None; diff --git a/app/src/executor.rs b/app/src/executor.rs index 143a66c0..681bff7d 100644 --- a/app/src/executor.rs +++ b/app/src/executor.rs @@ -1,6 +1,6 @@ -use core::{emit, files::FilesSorter, input::InputMode, tab::FinderCase, Ctx}; +use core::{emit, input::InputMode, tab::FinderCase, Ctx}; -use config::{keymap::{Control, Exec, Key, KeymapLayer}, manager::SortBy, KEYMAP}; +use config::{keymap::{Control, Exec, Key, KeymapLayer}, KEYMAP}; use shared::{optional_bool, Url}; pub(super) struct Executor; @@ -126,13 +126,7 @@ impl Executor { exec.named.contains_key("block"), exec.named.contains_key("confirm"), ), - "hidden" => { - cx.manager.active_mut().set_show_hidden(match exec.args.get(0).map(|s| s.as_str()) { - Some("show") => Some(true), - Some("hide") => Some(false), - _ => None, - }) - } + "hidden" => cx.manager.active_mut().hidden(exec), "search" => match exec.args.get(0).map(|s| s.as_str()).unwrap_or("") { "rg" => cx.manager.active_mut().search(true), "fd" => cx.manager.active_mut().search(false), @@ -160,13 +154,7 @@ impl Executor { // Sorting "sort" => { - let b = cx.manager.active_mut().set_sorter(FilesSorter { - by: SortBy::try_from(exec.args.get(0).cloned().unwrap_or_default()) - .unwrap_or_default(), - sensitive: exec.named.contains_key("sensitive"), - reverse: exec.named.contains_key("reverse"), - dir_first: exec.named.contains_key("dir_first"), - }); + let b = cx.manager.active_mut().sort(exec); cx.tasks.precache_size(&cx.manager.current().files); b } diff --git a/config/preset/yazi.toml b/config/preset/yazi.toml index 601ad845..e7f03db5 100644 --- a/config/preset/yazi.toml +++ b/config/preset/yazi.toml @@ -4,6 +4,7 @@ sort_by = "modified" sort_sensitive = true sort_reverse = true sort_dir_first = true +linemode = "none" show_hidden = false show_symlink = true diff --git a/config/src/manager/linemode.rs b/config/src/manager/linemode.rs new file mode 100644 index 00000000..b87b98ed --- /dev/null +++ b/config/src/manager/linemode.rs @@ -0,0 +1,26 @@ +use anyhow::bail; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)] +#[serde(try_from = "String")] +pub enum Linemode { + #[default] + None, + Size, + Mtime, + Permissions, +} + +impl TryFrom for Linemode { + type Error = anyhow::Error; + + fn try_from(s: String) -> Result { + Ok(match s.as_str() { + "none" => Self::None, + "size" => Self::Size, + "mtime" => Self::Mtime, + "permissions" => Self::Permissions, + _ => bail!("invalid linemode value: {s}"), + }) + } +} diff --git a/config/src/manager/manager.rs b/config/src/manager/manager.rs index 69386b40..9f209a86 100644 --- a/config/src/manager/manager.rs +++ b/config/src/manager/manager.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use super::{ManagerLayout, SortBy}; +use super::{Linemode, ManagerLayout, SortBy}; use crate::MERGED_YAZI; #[derive(Debug, Deserialize, Serialize)] @@ -14,6 +14,7 @@ pub struct Manager { pub sort_dir_first: bool, // Display + pub linemode: Linemode, pub show_hidden: bool, pub show_symlink: bool, } diff --git a/config/src/manager/mod.rs b/config/src/manager/mod.rs index 08394cbf..607f874e 100644 --- a/config/src/manager/mod.rs +++ b/config/src/manager/mod.rs @@ -1,7 +1,9 @@ mod layout; +mod linemode; mod manager; mod sorting; pub use layout::*; +pub use linemode::*; pub use manager::*; pub use sorting::*; diff --git a/config/src/manager/sorting.rs b/config/src/manager/sorting.rs index 35c937eb..39a6ae01 100644 --- a/config/src/manager/sorting.rs +++ b/config/src/manager/sorting.rs @@ -1,3 +1,5 @@ +use std::str::FromStr; + use anyhow::bail; use serde::{Deserialize, Serialize}; @@ -5,6 +7,7 @@ use serde::{Deserialize, Serialize}; #[serde(try_from = "String")] pub enum SortBy { #[default] + None, Alphabetical, Created, Modified, @@ -12,11 +15,12 @@ pub enum SortBy { Size, } -impl TryFrom for SortBy { - type Error = anyhow::Error; +impl FromStr for SortBy { + type Err = anyhow::Error; - fn try_from(s: String) -> Result { - Ok(match s.as_str() { + fn from_str(s: &str) -> Result { + Ok(match s { + "none" => Self::None, "alphabetical" => Self::Alphabetical, "created" => Self::Created, "modified" => Self::Modified, @@ -26,3 +30,9 @@ impl TryFrom for SortBy { }) } } + +impl TryFrom for SortBy { + type Error = anyhow::Error; + + fn try_from(s: String) -> Result { Self::from_str(&s) } +} diff --git a/config/src/theme/color.rs b/config/src/theme/color.rs index db154cc0..71c212c8 100644 --- a/config/src/theme/color.rs +++ b/config/src/theme/color.rs @@ -18,7 +18,7 @@ impl FromStr for Color { impl TryFrom for Color { type Error = anyhow::Error; - fn try_from(s: String) -> Result { Self::from_str(s.as_str()) } + fn try_from(s: String) -> Result { Self::from_str(&s) } } impl From for ratatui::style::Color { diff --git a/core/src/files/sorter.rs b/core/src/files/sorter.rs index 47ad4a1e..c336a3bf 100644 --- a/core/src/files/sorter.rs +++ b/core/src/files/sorter.rs @@ -1,11 +1,11 @@ use std::{cmp::Ordering, collections::BTreeMap, mem}; -use config::{manager::SortBy, MANAGER}; +use config::manager::SortBy; use shared::{natsort, Url}; use super::File; -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Default, PartialEq)] pub struct FilesSorter { pub by: SortBy, pub sensitive: bool, @@ -13,17 +13,6 @@ pub struct FilesSorter { pub dir_first: bool, } -impl Default for FilesSorter { - fn default() -> Self { - Self { - by: MANAGER.sort_by, - sensitive: MANAGER.sort_sensitive, - reverse: MANAGER.sort_reverse, - dir_first: MANAGER.sort_dir_first, - } - } -} - impl FilesSorter { pub(super) fn sort(&self, items: &mut Vec, sizes: &BTreeMap) -> bool { if items.is_empty() { @@ -31,6 +20,7 @@ impl FilesSorter { } match self.by { + SortBy::None => return false, SortBy::Alphabetical => items.sort_unstable_by(|a, b| { if self.sensitive { return self.cmp(&*a.url, &*b.url, self.promote(a, b)); @@ -98,7 +88,7 @@ impl FilesSorter { *items = new; } - #[inline] + #[inline(always)] #[allow(clippy::collapsible_else_if)] fn cmp(&self, a: T, b: T, promote: Ordering) -> Ordering { if promote != Ordering::Equal { @@ -108,7 +98,7 @@ impl FilesSorter { } } - #[inline] + #[inline(always)] fn promote(&self, a: &File, b: &File) -> Ordering { if self.dir_first { b.is_dir().cmp(&a.is_dir()) } else { Ordering::Equal } } diff --git a/core/src/manager/commands/peek.rs b/core/src/manager/commands/peek.rs index fb271a1a..0eb247e1 100644 --- a/core/src/manager/commands/peek.rs +++ b/core/src/manager/commands/peek.rs @@ -3,12 +3,12 @@ use crate::manager::Manager; impl Manager { pub fn peek(&mut self, sequent: bool, show_image: bool) -> bool { let Some(hovered) = self.hovered().cloned() else { - return self.active_mut().preview_reset(); + return self.active_mut().preview.reset(|_| true); }; let url = &hovered.url; if !show_image { - self.active_mut().preview_reset_image(); + self.active_mut().preview.reset(|l| l.is_image()); } if hovered.is_dir() { diff --git a/core/src/manager/tabs.rs b/core/src/manager/tabs.rs index a8bb3537..708d2a2f 100644 --- a/core/src/manager/tabs.rs +++ b/core/src/manager/tabs.rs @@ -23,8 +23,8 @@ impl Tabs { } let mut tab = Tab::from(url); - tab.set_show_hidden(Some(self.active().show_hidden)); - tab.set_sorter(self.active().sorter); + tab.conf = self.active().conf; + tab.apply_files_attrs(false); self.items.insert(self.idx + 1, tab); self.set_idx(self.idx + 1); @@ -83,7 +83,7 @@ impl Tabs { #[inline] fn set_idx(&mut self, idx: usize) { self.idx = idx; - self.active_mut().preview_reset_image(); + self.active_mut().preview.reset(|l| l.is_image()); emit!(Refresh); } } diff --git a/core/src/tab/commands/escape.rs b/core/src/tab/commands/escape.rs index 6dd5ba64..b77747a8 100644 --- a/core/src/tab/commands/escape.rs +++ b/core/src/tab/commands/escape.rs @@ -38,8 +38,8 @@ impl Tab { fn escape_search(&mut self) -> bool { self.search_stop() } pub fn escape(&mut self, opt: impl Into) -> bool { - let opt = opt.into(); - if opt.0 == 0 { + let opt = opt.into().0; + if opt == 0 { return self.escape_find() || self.escape_visual() || self.escape_select() @@ -47,16 +47,16 @@ impl Tab { } let mut b = false; - if opt.0 & 0b0001 != 0 { + if opt & 0b0001 != 0 { b |= self.escape_find(); } - if opt.0 & 0b0010 != 0 { + if opt & 0b0010 != 0 { b |= self.escape_visual(); } - if opt.0 & 0b0100 != 0 { + if opt & 0b0100 != 0 { b |= self.escape_select(); } - if opt.0 & 0b1000 != 0 { + if opt & 0b1000 != 0 { b |= self.escape_search(); } b diff --git a/core/src/tab/commands/hidden.rs b/core/src/tab/commands/hidden.rs new file mode 100644 index 00000000..bf2a289a --- /dev/null +++ b/core/src/tab/commands/hidden.rs @@ -0,0 +1,18 @@ +use config::keymap::Exec; + +use crate::{emit, tab::Tab}; + +impl Tab { + pub fn hidden(&mut self, e: &Exec) -> bool { + self.conf.show_hidden = match e.args.get(0).map(|s| s.as_bytes()) { + Some(b"show") => true, + Some(b"hide") => false, + _ => !self.conf.show_hidden, + }; + if self.apply_files_attrs(false) { + emit!(Peek); + return true; + } + false + } +} diff --git a/core/src/tab/commands/mod.rs b/core/src/tab/commands/mod.rs index bbafe0b2..370ba68a 100644 --- a/core/src/tab/commands/mod.rs +++ b/core/src/tab/commands/mod.rs @@ -5,9 +5,11 @@ mod copy; mod enter; mod escape; mod find; +mod hidden; mod jump; mod leave; mod search; mod select; mod shell; +mod sort; mod visual_mode; diff --git a/core/src/tab/commands/search.rs b/core/src/tab/commands/search.rs index 901c4ce4..c471baa2 100644 --- a/core/src/tab/commands/search.rs +++ b/core/src/tab/commands/search.rs @@ -13,7 +13,7 @@ impl Tab { } let mut cwd = self.current.cwd.clone(); - let hidden = self.show_hidden; + let hidden = self.conf.show_hidden; self.search = Some(tokio::spawn(async move { let Some(Ok(subject)) = emit!(Input(InputOpt::top("Search:"))).recv().await else { @@ -49,7 +49,7 @@ impl Tab { handle.abort(); } if self.current.cwd.is_search() { - self.preview_reset_image(); + self.preview.reset(|l| l.is_image()); let rep = self.history_new(&self.current.cwd.to_regular()); drop(mem::replace(&mut self.current, rep)); diff --git a/core/src/tab/commands/sort.rs b/core/src/tab/commands/sort.rs new file mode 100644 index 00000000..8683d512 --- /dev/null +++ b/core/src/tab/commands/sort.rs @@ -0,0 +1,18 @@ +use std::str::FromStr; + +use config::{keymap::Exec, manager::SortBy}; + +use crate::tab::Tab; + +impl Tab { + pub fn sort(&mut self, e: &Exec) -> bool { + if let Some(by) = e.args.get(0) { + self.conf.sort_by = SortBy::from_str(by).unwrap_or_default(); + } + self.conf.sort_sensitive = e.named.contains_key("sensitive"); + self.conf.sort_reverse = e.named.contains_key("reverse"); + self.conf.sort_dir_first = e.named.contains_key("dir_first"); + + self.apply_files_attrs(false) + } +} diff --git a/core/src/tab/config.rs b/core/src/tab/config.rs new file mode 100644 index 00000000..2f4ebf83 --- /dev/null +++ b/core/src/tab/config.rs @@ -0,0 +1,50 @@ +use config::{manager::{Linemode, SortBy}, MANAGER}; + +use crate::files::FilesSorter; + +#[derive(Clone, Copy, PartialEq)] +pub struct Config { + // Sorting + pub sort_by: SortBy, + pub sort_sensitive: bool, + pub sort_reverse: bool, + pub sort_dir_first: bool, + + // Display + pub linemode: Linemode, + pub show_hidden: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + // Sorting + sort_by: MANAGER.sort_by, + sort_sensitive: MANAGER.sort_sensitive, + sort_reverse: MANAGER.sort_reverse, + sort_dir_first: MANAGER.sort_dir_first, + + // Display + linemode: MANAGER.linemode, + show_hidden: MANAGER.show_hidden, + } + } +} + +impl Config { + pub(super) fn patch(&mut self, f: F) -> bool { + let old = *self; + f(self); + *self != old + } + + #[inline] + pub(super) fn sorter(&self) -> FilesSorter { + FilesSorter { + by: self.sort_by, + sensitive: self.sort_sensitive, + reverse: self.sort_reverse, + dir_first: self.sort_dir_first, + } + } +} diff --git a/core/src/tab/mod.rs b/core/src/tab/mod.rs index 36df8142..ebcd998e 100644 --- a/core/src/tab/mod.rs +++ b/core/src/tab/mod.rs @@ -1,11 +1,13 @@ mod backstack; mod commands; +mod config; mod finder; mod folder; mod mode; mod tab; pub use backstack::*; +pub use config::*; pub use finder::*; pub use folder::*; pub use mode::*; diff --git a/core/src/tab/tab.rs b/core/src/tab/tab.rs index b94e0884..0d6770b0 100644 --- a/core/src/tab/tab.rs +++ b/core/src/tab/tab.rs @@ -1,26 +1,24 @@ use std::{borrow::Cow, collections::BTreeMap}; use anyhow::Result; -use config::MANAGER; use shared::Url; use tokio::task::JoinHandle; -use super::{Backstack, Finder, Folder, Mode}; -use crate::{emit, files::{File, FilesSorter}, preview::{Preview, PreviewLock}}; +use super::{Backstack, Config, Finder, Folder, Mode}; +use crate::{files::File, preview::{Preview, PreviewLock}}; pub struct Tab { pub mode: Mode, + pub conf: Config, pub current: Folder, pub parent: Option, pub backstack: Backstack, pub history: BTreeMap, - pub preview: Preview, + pub preview: Preview, pub finder: Option, pub(super) search: Option>>, - pub sorter: FilesSorter, - pub show_hidden: bool, } impl From for Tab { @@ -34,12 +32,12 @@ impl From for Tab { backstack: Backstack::new(url), history: Default::default(), - preview: Default::default(), + preview: Default::default(), finder: None, search: None, - sorter: Default::default(), - show_hidden: MANAGER.show_hidden, + + conf: Default::default(), } } } @@ -63,7 +61,7 @@ impl Tab { pub fn update_preview(&mut self, lock: PreviewLock) -> bool { let Some(hovered) = self.current.hovered().map(|h| &h.url) else { - return self.preview_reset(); + return self.preview.reset(|_| true); }; if lock.url != *hovered { @@ -101,45 +99,13 @@ impl Tab { self.history.remove(url).unwrap_or_else(|| Folder::from(url)) } - // --- Preview - #[inline] - pub fn preview_reset(&mut self) -> bool { self.preview.reset(|_| true) } - - #[inline] - pub fn preview_reset_image(&mut self) -> bool { self.preview.reset(|l| l.is_image()) } - - // --- Sorter - pub fn set_sorter(&mut self, sorter: FilesSorter) -> bool { - if sorter == self.sorter { - return false; - } - - self.sorter = sorter; - self.apply_files_attrs(false) - } - - // --- Show hidden - pub fn set_show_hidden(&mut self, state: Option) -> bool { - let state = state.unwrap_or(!self.show_hidden); - if state == self.show_hidden { - return false; - } - - self.show_hidden = state; - if self.apply_files_attrs(false) { - emit!(Peek); - return true; - } - false - } - pub fn apply_files_attrs(&mut self, just_preview: bool) -> bool { let mut b = false; if let Some(f) = self.current.hovered().filter(|h| h.is_dir()).and_then(|h| self.history.get_mut(&h.url)) { - b |= f.files.set_show_hidden(self.show_hidden); - b |= f.files.set_sorter(self.sorter); + b |= f.files.set_show_hidden(self.conf.show_hidden); + b |= f.files.set_sorter(self.conf.sorter()); } if just_preview { @@ -147,12 +113,12 @@ impl Tab { } let hovered = self.current.hovered().map(|h| h.url()); - b |= self.current.files.set_show_hidden(self.show_hidden); - b |= self.current.files.set_sorter(self.sorter); + b |= self.current.files.set_show_hidden(self.conf.show_hidden); + b |= self.current.files.set_sorter(self.conf.sorter()); if let Some(parent) = self.parent.as_mut() { - b |= parent.files.set_show_hidden(self.show_hidden); - b |= parent.files.set_sorter(self.sorter); + b |= parent.files.set_show_hidden(self.conf.show_hidden); + b |= parent.files.set_sorter(self.conf.sorter()); } self.current.repos(hovered); diff --git a/cspell.json b/cspell.json index 6837af57..c3e56f22 100644 --- a/cspell.json +++ b/cspell.json @@ -1 +1 @@ -{"version":"0.2","language":"en","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","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan"]} +{"language":"en","flagWords":[],"version":"0.2","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","Succ","Succ","cand","fileencoding","foldmethod","lightgreen","darkgray","lightred","lightyellow","lightcyan","linemode"]} diff --git a/plugin/src/components/base.rs b/plugin/src/components/base.rs index 52889050..3245b2c2 100644 --- a/plugin/src/components/base.rs +++ b/plugin/src/components/base.rs @@ -21,9 +21,8 @@ impl Base { } pub fn render(self, cx: &core::Ctx, buf: &mut ratatui::buffer::Buffer) { - match self.kind { - 0 => super::Preview::new(cx).render(self.area, buf), - _ => {} + if self.kind == 0 { + super::Preview::new(cx).render(self.area, buf) } } }