refactor: tab-specific config

This commit is contained in:
sxyazi 2023-10-20 09:10:07 +08:00
parent 9d4ba510df
commit bed8172347
No known key found for this signature in database
21 changed files with 177 additions and 104 deletions

View File

@ -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<oneshot::Sender<()>>) {
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;

View File

@ -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
}

View File

@ -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

View File

@ -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<String> for Linemode {
type Error = anyhow::Error;
fn try_from(s: String) -> Result<Self, Self::Error> {
Ok(match s.as_str() {
"none" => Self::None,
"size" => Self::Size,
"mtime" => Self::Mtime,
"permissions" => Self::Permissions,
_ => bail!("invalid linemode value: {s}"),
})
}
}

View File

@ -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,
}

View File

@ -1,7 +1,9 @@
mod layout;
mod linemode;
mod manager;
mod sorting;
pub use layout::*;
pub use linemode::*;
pub use manager::*;
pub use sorting::*;

View File

@ -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<String> for SortBy {
type Error = anyhow::Error;
impl FromStr for SortBy {
type Err = anyhow::Error;
fn try_from(s: String) -> Result<Self, Self::Error> {
Ok(match s.as_str() {
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"none" => Self::None,
"alphabetical" => Self::Alphabetical,
"created" => Self::Created,
"modified" => Self::Modified,
@ -26,3 +30,9 @@ impl TryFrom<String> for SortBy {
})
}
}
impl TryFrom<String> for SortBy {
type Error = anyhow::Error;
fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_str(&s) }
}

View File

@ -18,7 +18,7 @@ impl FromStr for Color {
impl TryFrom<String> for Color {
type Error = anyhow::Error;
fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_str(s.as_str()) }
fn try_from(s: String) -> Result<Self, Self::Error> { Self::from_str(&s) }
}
impl From<Color> for ratatui::style::Color {

View File

@ -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<File>, sizes: &BTreeMap<Url, u64>) -> 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<T: Ord>(&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 }
}

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -38,8 +38,8 @@ impl Tab {
fn escape_search(&mut self) -> bool { self.search_stop() }
pub fn escape(&mut self, opt: impl Into<Opt>) -> 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

View File

@ -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
}
}

View File

@ -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;

View File

@ -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));

View File

@ -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)
}
}

50
core/src/tab/config.rs Normal file
View File

@ -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<F: FnOnce(&mut Self)>(&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,
}
}
}

View File

@ -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::*;

View File

@ -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<Folder>,
pub backstack: Backstack<Url>,
pub history: BTreeMap<Url, Folder>,
pub preview: Preview,
pub preview: Preview,
pub finder: Option<Finder>,
pub(super) search: Option<JoinHandle<Result<()>>>,
pub sorter: FilesSorter,
pub show_hidden: bool,
}
impl From<Url> for Tab {
@ -34,12 +32,12 @@ impl From<Url> 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>) -> 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);

View File

@ -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"]}

View File

@ -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)
}
}
}