Skip to content

Commit

Permalink
refactor: simplify filesystem design to improve performance (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
sxyazi authored Aug 29, 2023
1 parent 2b70107 commit e31bc6a
Show file tree
Hide file tree
Showing 23 changed files with 520 additions and 342 deletions.
4 changes: 2 additions & 2 deletions app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl App {
let calc = matches!(op, FilesOp::Read(..) | FilesOp::Search(..));
let b = match op {
FilesOp::Read(..) => manager.update_read(op),
FilesOp::Sort(..) => manager.update_read(op),
FilesOp::Size(..) => manager.update_read(op),
FilesOp::Search(..) => manager.update_search(op),
FilesOp::IOErr(..) => manager.update_ioerr(op),
};
Expand All @@ -144,7 +144,7 @@ impl App {
}
Event::Pages(page) => {
if manager.current().page == page {
let targets = self.cx.manager.current().paginate().into_iter().map(|(_, f)| f).collect();
let targets = self.cx.manager.current().paginate();
tasks.precache_mime(targets, &self.cx.manager.mimetype);
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl Ctx {
}
Position::Hovered(rect @ Rect { mut x, y, width, height }) => {
let Some(r) =
self.manager.hovered().and_then(|h| self.manager.current().rect_current(&h.path))
self.manager.hovered().and_then(|h| self.manager.current().rect_current(h.path()))
else {
return self.area(&Position::Top(*rect));
};
Expand Down
16 changes: 9 additions & 7 deletions app/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl Executor {
}
}
"remove" => {
let targets = cx.manager.selected().into_iter().map(|p| p.path()).collect();
let targets = cx.manager.selected().into_iter().map(|f| f.path_owned()).collect();
cx.tasks.file_remove(targets, exec.named.contains_key("permanently"))
}
"create" => cx.manager.create(),
Expand All @@ -117,11 +117,13 @@ impl Executor {
exec.named.contains_key("block"),
exec.named.contains_key("confirm"),
),
"hidden" => cx.manager.current_mut().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().set_show_hidden(match exec.args.get(0).map(|s| s.as_str()) {
Some("show") => Some(true),
Some("hide") => Some(false),
_ => None,
})
}
"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),
Expand All @@ -135,7 +137,7 @@ impl Executor {

// Sorting
"sort" => {
let b = cx.manager.current_mut().files.set_sorter(FilesSorter {
let b = cx.manager.active_mut().set_sorter(FilesSorter {
by: SortBy::try_from(exec.args.get(0).cloned().unwrap_or_default())
.unwrap_or_default(),
reverse: exec.named.contains_key("reverse"),
Expand Down
19 changes: 10 additions & 9 deletions app/src/manager/folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<'a> Folder<'a> {
THEME
.filetypes
.iter()
.find(|x| x.matches(&file.path, mimetype.get(&file.path).cloned(), file.meta.is_dir()))
.find(|x| x.matches(file.path(), mimetype.get(file.path()), file.is_dir()))
.map(|x| x.style.get())
.unwrap_or_else(Style::new)
}
Expand All @@ -56,16 +56,17 @@ impl<'a> Widget for Folder<'a> {
let items = window
.iter()
.enumerate()
.map(|(i, (k, v))| {
.map(|(i, f)| {
let icon = THEME
.icons
.iter()
.find(|x| x.name.match_path(k, Some(v.meta.is_dir())))
.find(|x| x.name.match_path(f.path(), Some(f.is_dir())))
.map(|x| x.display.as_ref())
.unwrap_or("");

if (!self.is_selection && v.is_selected)
|| (self.is_selection && mode.pending(i, v.is_selected))
let is_selected = self.folder.files.is_selected(f.path());
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 },
Expand All @@ -77,17 +78,17 @@ impl<'a> Widget for Folder<'a> {
);
}

let hovered = matches!(self.folder.hovered, Some(ref h) if h.path == *k);
let hovered = matches!(self.folder.hovered, Some(ref h) if h.path() == f.path());
let style = if self.is_preview && hovered {
THEME.preview.hovered.get()
} else if hovered {
THEME.selection.hovered.get()
} else {
self.file_style(v)
self.file_style(f)
};

let mut path = format!(" {icon} {}", readable_path(k, &self.folder.cwd));
if let Some(ref link_to) = v.link_to {
let mut path = format!(" {icon} {}", readable_path(f.path(), &self.folder.cwd));
if let Some(link_to) = f.link_to() {
if MANAGER.show_symlink {
path.push_str(&format!(" -> {}", link_to.display()));
}
Expand Down
2 changes: 1 addition & 1 deletion app/src/manager/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl<'a> Preview<'a> {
impl<'a> Widget for Preview<'a> {
fn render(self, area: Rect, buf: &mut Buffer) {
let manager = &self.cx.manager;
let Some(hovered) = manager.hovered().map(|h| &h.path) else {
let Some(hovered) = manager.hovered().map(|h| h.path()) else {
return;
};

Expand Down
4 changes: 2 additions & 2 deletions app/src/status/left.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ impl<'a> Widget for Left<'a> {

if let Some(h) = &manager.hovered {
// Length
if let Some(len) = h.length {
if let Some(len) = h.length() {
spans.push(Span::styled(format!(" {} ", readable_size(len)), body.bg().fg(**primary)));
spans.push(Span::styled(&separator.closing, body.fg()));
}

// Filename
spans.push(Span::raw(format!(" {} ", h.name().unwrap())));
spans.push(Span::raw(format!(" {} ", h.name_display().unwrap())));
}

Paragraph::new(Line::from(spans)).render(area, buf);
Expand Down
2 changes: 1 addition & 1 deletion app/src/status/right.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl Widget for Right<'_> {
#[cfg(not(target_os = "windows"))]
if let Some(h) = &manager.hovered {
use std::os::unix::prelude::PermissionsExt;
spans.extend(self.permissions(&shared::file_mode(h.meta.permissions().mode())))
spans.extend(self.permissions(&shared::file_mode(h.meta().permissions().mode())))
}

// Position
Expand Down
4 changes: 2 additions & 2 deletions config/src/theme/filetype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ pub struct Filetype {
}

impl Filetype {
pub fn matches(&self, path: &Path, mime: Option<String>, is_dir: bool) -> bool {
pub fn matches(&self, path: &Path, mime: Option<impl AsRef<str>>, is_dir: bool) -> bool {
if self.name.as_ref().map_or(false, |e| e.match_path(path, Some(is_dir))) {
return true;
}
if let Some(mime) = mime {
return self.mime.as_ref().map_or(false, |m| m.matches(&mime));
return self.mime.as_ref().map_or(false, |m| m.matches(mime));
}
false
}
Expand Down
64 changes: 48 additions & 16 deletions core/src/files/file.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
use std::{borrow::Cow, fs::Metadata, path::{Path, PathBuf}};
use std::{borrow::Cow, ffi::OsStr, fs::Metadata, path::{Path, PathBuf}};

use anyhow::Result;
use tokio::fs;

#[derive(Clone, Debug)]
pub struct File {
pub path: PathBuf,
pub meta: Metadata,
pub length: Option<u64>,
pub link_to: Option<PathBuf>,
pub is_link: bool,
pub is_hidden: bool,
pub is_selected: bool,
pub(super) path: PathBuf,
pub(super) meta: Metadata,
pub(super) length: Option<u64>,
pub(super) link_to: Option<PathBuf>,
pub(super) is_link: bool,
pub(super) is_hidden: bool,
}

impl File {
#[inline]
pub async fn from(path: &Path) -> Result<File> {
pub async fn from(path: &Path) -> Result<Self> {
let meta = fs::metadata(path).await?;
Ok(Self::from_meta(path, meta).await)
}

pub async fn from_meta(path: &Path, mut meta: Metadata) -> File {
pub async fn from_meta(path: &Path, mut meta: Metadata) -> Self {
let is_link = meta.is_symlink();
let mut link_to = None;

Expand All @@ -32,20 +31,53 @@ impl File {

let length = if meta.is_dir() { None } else { Some(meta.len()) };
let is_hidden = path.file_name().map(|s| s.to_string_lossy().starts_with('.')).unwrap_or(false);
File { path: path.to_path_buf(), meta, length, link_to, is_link, is_hidden, is_selected: false }
Self { path: path.to_path_buf(), meta, length, link_to, is_link, is_hidden }
}
}

impl File {
// --- Path
#[inline]
pub fn path(&self) -> PathBuf { self.path.clone() }
pub fn path(&self) -> &PathBuf { &self.path }

#[inline]
pub fn set_path(mut self, path: &Path) -> Self {
self.path = path.to_path_buf();
self
pub fn set_path(&mut self, path: PathBuf) { self.path = path; }

#[inline]
pub fn path_owned(&self) -> PathBuf { self.path.clone() }

#[inline]
pub fn path_os_str(&self) -> &OsStr { self.path.as_os_str() }

#[inline]
pub fn name(&self) -> Option<&OsStr> { self.path.file_name() }

#[inline]
pub fn name_display(&self) -> Option<Cow<str>> {
self.path.file_name().map(|s| s.to_string_lossy())
}

#[inline]
pub fn name(&self) -> Option<Cow<str>> { self.path.file_name().map(|s| s.to_string_lossy()) }
pub fn stem(&self) -> Option<&OsStr> { self.path.file_stem() }

#[inline]
pub fn parent(&self) -> Option<&Path> { self.path.parent() }

// --- Meta
#[inline]
pub fn meta(&self) -> &Metadata { &self.meta }

#[inline]
pub fn is_file(&self) -> bool { self.meta.is_file() }

#[inline]
pub fn is_dir(&self) -> bool { self.meta.is_dir() }

// --- Length
#[inline]
pub fn length(&self) -> Option<u64> { self.length }

// --- Link to
#[inline]
pub fn link_to(&self) -> Option<&PathBuf> { self.link_to.as_ref() }
}
Loading

0 comments on commit e31bc6a

Please sign in to comment.