Skip to content

Commit

Permalink
perf: introduce URN to speed up large directory file sorting (#1622)
Browse files Browse the repository at this point in the history
  • Loading branch information
sxyazi authored Sep 9, 2024
1 parent d20b3d8 commit 3ee1209
Show file tree
Hide file tree
Showing 34 changed files with 283 additions and 195 deletions.
1 change: 0 additions & 1 deletion yazi-adapter/src/ueberzug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 82,6 @@ impl Ueberzug {
}

fn create_demon(adapter: Adapter) -> Result<Child> {
// TODO: demon
let result = Command::new("ueberzugpp")
.args(["layer", "-so", &adapter.to_string()])
.env("SPDLOG_LEVEL", if cfg!(debug_assertions) { "debug" } else { "" })
Expand Down
1 change: 1 addition & 0 deletions yazi-core/src/manager/commands/bulk_rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 95,7 @@ impl Manager {
}
}

// FIXME: consider old and new in the different directories
if !succeeded.is_empty() {
Pubsub::pub_from_bulk(succeeded.iter().map(|(u, f)| (u, f.url())).collect());
FilesOp::Upserting(cwd, succeeded).emit();
Expand Down
4 changes: 2 additions & 2 deletions yazi-core/src/manager/commands/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 40,9 @@ impl Manager {
// Refresh watcher
let mut to_watch = HashSet::with_capacity(3 * self.tabs.len());
for tab in self.tabs.iter() {
to_watch.insert(&tab.current.cwd);
to_watch.insert(tab.cwd());
if let Some(ref p) = tab.parent {
to_watch.insert(&p.cwd);
to_watch.insert(&p.loc);
}
if let Some(h) = tab.current.hovered().filter(|&h| h.is_dir()) {
to_watch.insert(h.url());
Expand Down
2 changes: 1 addition & 1 deletion yazi-core/src/manager/commands/open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 111,7 @@ impl Manager {

let find = |folder: Option<&Folder>| {
folder.is_some_and(|folder| {
folder.cwd == p && folder.files.iter().any(|f| f.is_dir() && url == f.url())
p == *folder.loc && folder.files.iter().any(|f| f.is_dir() && url == f.url())
})
};

Expand Down
2 changes: 1 addition & 1 deletion yazi-core/src/manager/commands/tab_create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 46,7 @@ impl Tabs {
} else {
tab.conf = self.active().conf.clone();
tab.apply_files_attrs();
tab.cd(self.active().current.cwd.clone());
tab.cd(self.active().cwd().clone());
}

self.items.insert(self.cursor 1, tab);
Expand Down
8 changes: 4 additions & 4 deletions yazi-core/src/manager/commands/update_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 47,9 @@ impl Manager {
let url = op.url();
tab.selected.apply_op(&op);

if tab.current.cwd == *url {
if url == tab.cwd() {
Self::update_current(tab, op, tasks);
} else if matches!(&tab.parent, Some(p) if p.cwd == *url) {
} else if matches!(&tab.parent, Some(p) if url == &*p.loc) {
Self::update_parent(tab, op);
} else if matches!(tab.current.hovered(), Some(h) if url == h.url()) {
Self::update_hovered(tab, op);
Expand All @@ -59,7 59,7 @@ impl Manager {
}

fn update_parent(tab: &mut Tab, op: Cow<FilesOp>) {
let cwd = tab.current.cwd.clone();
let cwd = tab.cwd().clone();
let leave = matches!(*op, FilesOp::Deleting(_, ref urls) if urls.contains(&cwd));

if let Some(f) = tab.parent.as_mut() {
Expand Down Expand Up @@ -108,7 108,7 @@ impl Manager {
}

fn update_history(tab: &mut Tab, op: Cow<FilesOp>) {
let leave = tab.parent.as_ref().and_then(|f| f.cwd.parent_url().map(|p| (&f.cwd, p))).is_some_and(
let leave = tab.parent.as_ref().and_then(|f| f.loc.parent_url().map(|p| (&f.loc, p))).is_some_and(
|(p, pp)| matches!(*op, FilesOp::Deleting(ref parent, ref urls) if *parent == pp && urls.contains(p)),
);

Expand Down
2 changes: 1 addition & 1 deletion yazi-core/src/manager/commands/update_paged.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 27,7 @@ impl Manager {
return;
};

if opt.only_if.is_some_and(|u| u != self.current().cwd) {
if opt.only_if.is_some_and(|u| u != *self.active().cwd()) {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion yazi-core/src/manager/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 41,7 @@ impl Manager {

impl Manager {
#[inline]
pub fn cwd(&self) -> &Url { &self.current().cwd }
pub fn cwd(&self) -> &Url { &self.current().loc }

#[inline]
pub fn active(&self) -> &Tab { self.tabs.active() }
Expand Down
7 changes: 5 additions & 2 deletions yazi-core/src/manager/watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 60,11 @@ impl Watcher {
}

pub(super) fn trigger_dirs(&self, folders: &[&Folder]) {
let todo: Vec<_> =
folders.iter().filter(|&f| f.cwd.is_regular()).map(|&f| (f.cwd.clone(), f.cha)).collect();
let todo: Vec<_> = folders
.iter()
.filter(|&f| f.loc.is_regular())
.map(|&f| (f.loc.url().clone(), f.cha))
.collect();
if todo.is_empty() {
return;
}
Expand Down
14 changes: 7 additions & 7 deletions yazi-core/src/tab/commands/cd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,33 39,33 @@ impl Tab {
return self.cd_interactive();
}

if self.current.cwd == opt.target {
if opt.target == *self.cwd() {
return;
}

// Take parent to history
if let Some(rep) = self.parent.take() {
self.history.insert(rep.cwd.clone(), rep);
self.history.insert(rep.loc.url().clone(), rep);
}

// Current
let rep = self.history_new(&opt.target);
let rep = self.history.remove_or(&opt.target);
let rep = mem::replace(&mut self.current, rep);
if rep.cwd.is_regular() {
self.history.insert(rep.cwd.clone(), rep);
if rep.loc.is_regular() {
self.history.insert(rep.loc.url().clone(), rep);
}

// Parent
if let Some(parent) = opt.target.parent_url() {
self.parent = Some(self.history_new(&parent));
self.parent = Some(self.history.remove_or(&parent));
}

// Backstack
if opt.target.is_regular() {
self.backstack.push(opt.target.clone());
}

Pubsub::pub_from_cd(self.idx, &self.current.cwd);
Pubsub::pub_from_cd(self.idx, self.cwd());
ManagerProxy::refresh();
render!();
}
Expand Down
4 changes: 2 additions & 2 deletions yazi-core/src/tab/commands/escape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 92,7 @@ impl Tab {
}

pub fn escape_search(&mut self) -> bool {
let b = self.current.cwd.is_search();
let b = self.cwd().is_search();
self.search_stop();

render_and!(b)
Expand All @@ -108,7 108,7 @@ impl Tab {
let urls: Vec<_> =
indices.into_iter().filter_map(|i| self.current.files.get(i)).map(|f| f.url()).collect();

let same = !self.current.cwd.is_search();
let same = !self.cwd().is_search();
if !select {
self.selected.remove_many(&urls, same);
} else if self.selected.add_many(&urls, same) != urls.len() {
Expand Down
4 changes: 2 additions & 2 deletions yazi-core/src/tab/commands/leave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 16,8 @@ impl Tab {
.current
.hovered()
.and_then(|h| h.parent())
.filter(|p| *p != self.current.cwd)
.or_else(|| self.current.cwd.parent_url())
.filter(|p| p != self.cwd())
.or_else(|| self.cwd().parent_url())
.map(|u| self.cd(u));
}
}
7 changes: 3 additions & 4 deletions yazi-core/src/tab/commands/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 44,10 @@ impl Tab {
handle.abort();
}

let mut cwd = self.current.cwd.clone();
let cwd = self.cwd().to_search(&opt.subject);
let hidden = self.conf.show_hidden;

self.search = Some(tokio::spawn(async move {
cwd = cwd.into_search(opt.subject.clone());
let rx = if opt.via == SearchOptVia::Rg {
external::rg(external::RgOpt {
cwd: cwd.clone(),
Expand Down Expand Up @@ -82,8 81,8 @@ impl Tab {
if let Some(handle) = self.search.take() {
handle.abort();
}
if self.current.cwd.is_search() {
let rep = self.history_new(&self.current.cwd.to_regular());
if self.cwd().is_search() {
let rep = self.history.remove_or(&self.cwd().to_regular());
drop(mem::replace(&mut self.current, rep));
ManagerProxy::refresh();
}
Expand Down
2 changes: 1 addition & 1 deletion yazi-core/src/tab/commands/select_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 31,7 @@ impl Tab {
None => iter.partition(|&u| self.selected.contains_key(u)),
};

let same = !self.current.cwd.is_search();
let same = !self.cwd().is_search();
render!(self.selected.remove_many(&removal, same) > 0);

let added = self.selected.add_many(&addition, same);
Expand Down
26 changes: 26 additions & 0 deletions yazi-core/src/tab/history.rs
Original file line number Diff line number Diff line change
@@ -0,0 1,26 @@
use std::{collections::HashMap, ops::{Deref, DerefMut}};

use yazi_fs::Folder;
use yazi_shared::fs::Url;

#[derive(Default)]
pub struct History(HashMap<Url, Folder>);

impl Deref for History {
type Target = HashMap<Url, Folder>;

#[inline]
fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for History {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl History {
#[inline]
pub fn remove_or(&mut self, url: &Url) -> Folder {
self.0.remove(url).unwrap_or_else(|| Folder::from(url))
}
}
2 changes: 2 additions & 0 deletions yazi-core/src/tab/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 2,7 @@ mod backstack;
mod commands;
mod config;
mod finder;
mod history;
mod mode;
mod preview;
mod selected;
Expand All @@ -10,6 11,7 @@ mod tab;
pub use backstack::*;
pub use config::*;
pub use finder::*;
pub use history::*;
pub use mode::*;
pub use preview::*;
pub use selected::*;
Expand Down
17 changes: 8 additions & 9 deletions yazi-core/src/tab/tab.rs
Original file line number Diff line number Diff line change
@@ -1,4 1,4 @@
use std::{collections::HashMap, iter};
use std::iter;

use anyhow::Result;
use ratatui::layout::Rect;
Expand All @@ -8,7 8,7 @@ use yazi_config::{popup::{Origin, Position}, LAYOUT};
use yazi_fs::{Folder, FolderStage};
use yazi_shared::{fs::Url, render};

use super::{Backstack, Config, Finder, Mode, Preview};
use super::{Backstack, Config, Finder, History, Mode, Preview};
use crate::tab::Selected;

#[derive(Default)]
Expand All @@ -20,7 20,7 @@ pub struct Tab {
pub parent: Option<Folder>,

pub backstack: Backstack<Url>,
pub history: HashMap<Url, Folder>,
pub history: History,
pub selected: Selected,

pub preview: Preview,
Expand All @@ -38,6 38,9 @@ impl Tab {

impl Tab {
// --- Current
#[inline]
pub fn cwd(&self) -> &Url { &self.current.loc }

pub fn hovered_rect(&self) -> Option<Rect> {
let y = self.current.files.position(self.current.hovered()?.url())? - self.current.offset;

Expand Down Expand Up @@ -83,10 86,6 @@ impl Tab {
}

// --- History
#[inline]
pub fn history_new(&mut self, url: &Url) -> Folder {
self.history.remove(url).unwrap_or_else(|| Folder::from(url))
}

#[inline]
pub fn hovered_folder(&self) -> Option<&Folder> {
Expand All @@ -113,8 112,8 @@ impl Tab {
apply(parent);

// The parent should always track the CWD
parent.hover(&self.current.cwd);
parent.tracing = parent.hovered().map(|h| h.url()) == Some(&self.current.cwd);
parent.hover(&self.current.loc);
parent.tracing = parent.hovered().map(|h| h.url()) == Some(&self.current.loc);
}

self
Expand Down
14 changes: 7 additions & 7 deletions yazi-fm/src/lives/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 46,11 @@ impl File {
Ok(cx.manager.mimetype.get(me.url()).cloned())
});
reg.add_method("prefix", |lua, me, ()| {
if !me.folder().cwd.is_search() {
if !me.folder().loc.is_search() {
return Ok(None);
}

let mut p = me.url().strip_prefix(&me.folder().cwd).unwrap_or(me.url()).components();
let mut p = me.url().strip_prefix(&me.folder().loc).unwrap_or(me.url()).components();
p.next_back();
Some(lua.create_string(p.as_path().as_os_str().as_encoded_bytes())).transpose()
});
Expand All @@ -77,7 77,7 @@ impl File {
});
reg.add_method("is_marked", |_, me, ()| {
use yazi_core::tab::Mode::*;
if !me.tab().mode.is_visual() || me.folder().cwd != me.tab().current.cwd {
if !me.tab().mode.is_visual() || me.folder().loc != me.tab().current.loc {
return Ok(0u8);
}

Expand All @@ -89,11 89,11 @@ impl File {
});
reg.add_method("is_selected", |_, me, ()| Ok(me.tab().selected.contains_key(me.url())));
reg.add_method("in_parent", |_, me, ()| {
Ok(me.tab().parent.as_ref().is_some_and(|f| me.folder().cwd == f.cwd))
Ok(me.tab().parent.as_ref().is_some_and(|f| me.folder().loc == f.loc))
});
reg.add_method("in_current", |_, me, ()| Ok(me.folder().cwd == me.tab().current.cwd));
reg.add_method("in_current", |_, me, ()| Ok(me.folder().loc == me.tab().current.loc));
reg.add_method("in_preview", |_, me, ()| {
Ok(me.tab().current.hovered().is_some_and(|f| me.folder().cwd == *f.url()))
Ok(me.tab().current.hovered().is_some_and(|f| f.url() == &*me.folder().loc))
});
reg.add_method("found", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?;
Expand All @@ -113,7 113,7 @@ impl File {
let Some(finder) = &cx.manager.active().finder else {
return Ok(None);
};
if me.folder().cwd != me.tab().current.cwd {
if me.folder().loc != me.tab().current.loc {
return Ok(None);
}
let Some(h) = finder.filter.highlighted(me.name()) else {
Expand Down
2 changes: 1 addition & 1 deletion yazi-fm/src/lives/folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 38,7 @@ impl Folder {

pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<Self>(|reg| {
reg.add_field_method_get("cwd", |lua, me| Url::cast(lua, me.cwd.clone()));
reg.add_field_method_get("cwd", |lua, me| Url::cast(lua, me.loc.url().clone()));
reg.add_field_method_get("files", |_, me| Files::make(0..me.files.len(), me, me.tab()));
reg.add_field_method_get("stage", |lua, me| lua.create_any_userdata(me.stage));
reg.add_field_method_get("window", |_, me| Files::make(me.window.clone(), me, me.tab()));
Expand Down
10 changes: 1 addition & 9 deletions yazi-fm/src/lives/tab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 24,7 @@ impl Tab {
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<Self>(|reg| {
reg.add_method("name", |lua, me, ()| {
Some(
lua.create_string(
me.current
.cwd
.file_name()
.map_or(me.current.cwd.as_os_str().as_encoded_bytes(), |n| n.as_encoded_bytes()),
),
)
.transpose()
Some(lua.create_string(me.current.loc.name().as_encoded_bytes())).transpose()
});

reg.add_field_method_get("mode", |_, me| Mode::make(&me.mode));
Expand Down
Loading

0 comments on commit 3ee1209

Please sign in to comment.