diff --git a/yazi-adapter/src/ueberzug.rs b/yazi-adapter/src/ueberzug.rs index 79155c39..f235bd43 100644 --- a/yazi-adapter/src/ueberzug.rs +++ b/yazi-adapter/src/ueberzug.rs @@ -82,7 +82,6 @@ impl Ueberzug { } fn create_demon(adapter: Adapter) -> Result { - // TODO: demon let result = Command::new("ueberzugpp") .args(["layer", "-so", &adapter.to_string()]) .env("SPDLOG_LEVEL", if cfg!(debug_assertions) { "debug" } else { "" }) diff --git a/yazi-core/src/manager/commands/hover.rs b/yazi-core/src/manager/commands/hover.rs index 215218e4..691ce24b 100644 --- a/yazi-core/src/manager/commands/hover.rs +++ b/yazi-core/src/manager/commands/hover.rs @@ -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()); diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index 2594773a..76ed3205 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -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()) }) }; diff --git a/yazi-core/src/manager/commands/tab_create.rs b/yazi-core/src/manager/commands/tab_create.rs index d1ca7ba1..d19526a7 100644 --- a/yazi-core/src/manager/commands/tab_create.rs +++ b/yazi-core/src/manager/commands/tab_create.rs @@ -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); diff --git a/yazi-core/src/manager/commands/update_files.rs b/yazi-core/src/manager/commands/update_files.rs index aabb6b0c..b0cf29a8 100644 --- a/yazi-core/src/manager/commands/update_files.rs +++ b/yazi-core/src/manager/commands/update_files.rs @@ -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); @@ -59,7 +59,7 @@ impl Manager { } fn update_parent(tab: &mut Tab, op: Cow) { - 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() { @@ -108,7 +108,7 @@ impl Manager { } fn update_history(tab: &mut Tab, op: Cow) { - 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)), ); diff --git a/yazi-core/src/manager/commands/update_paged.rs b/yazi-core/src/manager/commands/update_paged.rs index 6c28791b..b6763b1d 100644 --- a/yazi-core/src/manager/commands/update_paged.rs +++ b/yazi-core/src/manager/commands/update_paged.rs @@ -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; } diff --git a/yazi-core/src/manager/manager.rs b/yazi-core/src/manager/manager.rs index 0b5545f8..d7c9f98e 100644 --- a/yazi-core/src/manager/manager.rs +++ b/yazi-core/src/manager/manager.rs @@ -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() } diff --git a/yazi-core/src/manager/watcher.rs b/yazi-core/src/manager/watcher.rs index e01159a8..9be552fd 100644 --- a/yazi-core/src/manager/watcher.rs +++ b/yazi-core/src/manager/watcher.rs @@ -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; } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index dfa148af..5cebaf09 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -39,25 +39,25 @@ 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 @@ -65,7 +65,7 @@ impl Tab { 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!(); } diff --git a/yazi-core/src/tab/commands/escape.rs b/yazi-core/src/tab/commands/escape.rs index a363c4bc..4f61306c 100644 --- a/yazi-core/src/tab/commands/escape.rs +++ b/yazi-core/src/tab/commands/escape.rs @@ -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) @@ -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() { diff --git a/yazi-core/src/tab/commands/leave.rs b/yazi-core/src/tab/commands/leave.rs index 85d96fe6..440614f1 100644 --- a/yazi-core/src/tab/commands/leave.rs +++ b/yazi-core/src/tab/commands/leave.rs @@ -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)); } } diff --git a/yazi-core/src/tab/commands/reveal.rs b/yazi-core/src/tab/commands/reveal.rs index 652fa4af..46df9fb8 100644 --- a/yazi-core/src/tab/commands/reveal.rs +++ b/yazi-core/src/tab/commands/reveal.rs @@ -28,12 +28,9 @@ impl Tab { let Some(parent) = opt.target.parent_url() else { return; }; - let Ok(file) = File::from_dummy(opt.target.clone(), None) else { - return; - }; self.cd(parent.clone()); - FilesOp::Creating(parent, vec![file]).emit(); + FilesOp::Creating(parent, vec![File::from_dummy(opt.target.clone(), None)]).emit(); ManagerProxy::hover(Some(opt.target), self.idx); } } diff --git a/yazi-core/src/tab/commands/search.rs b/yazi-core/src/tab/commands/search.rs index 5d8655ad..b7a73c1f 100644 --- a/yazi-core/src/tab/commands/search.rs +++ b/yazi-core/src/tab/commands/search.rs @@ -44,7 +44,7 @@ impl Tab { handle.abort(); } - let cwd = self.current.cwd.to_search(&opt.subject); + let cwd = self.cwd().to_search(&opt.subject); let hidden = self.conf.show_hidden; self.search = Some(tokio::spawn(async move { @@ -81,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(); } diff --git a/yazi-core/src/tab/commands/select_all.rs b/yazi-core/src/tab/commands/select_all.rs index e01391bb..4a60a646 100644 --- a/yazi-core/src/tab/commands/select_all.rs +++ b/yazi-core/src/tab/commands/select_all.rs @@ -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); diff --git a/yazi-core/src/tab/history.rs b/yazi-core/src/tab/history.rs new file mode 100644 index 00000000..39fba485 --- /dev/null +++ b/yazi-core/src/tab/history.rs @@ -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); + +impl Deref for History { + type Target = HashMap; + + #[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)) + } +} diff --git a/yazi-core/src/tab/mod.rs b/yazi-core/src/tab/mod.rs index 08d7a616..0e7d4e69 100644 --- a/yazi-core/src/tab/mod.rs +++ b/yazi-core/src/tab/mod.rs @@ -2,6 +2,7 @@ mod backstack; mod commands; mod config; mod finder; +mod history; mod mode; mod preview; mod selected; @@ -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::*; diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index fc987a12..1b443029 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, iter}; +use std::iter; use anyhow::Result; use ratatui::layout::Rect; @@ -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)] @@ -20,7 +20,7 @@ pub struct Tab { pub parent: Option, pub backstack: Backstack, - pub history: HashMap, + pub history: History, pub selected: Selected, pub preview: Preview, @@ -38,6 +38,9 @@ impl Tab { impl Tab { // --- Current + #[inline] + pub fn cwd(&self) -> &Url { &self.current.loc } + pub fn hovered_rect(&self) -> Option { let y = self.current.files.position(self.current.hovered()?.url())? - self.current.offset; @@ -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> { @@ -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 diff --git a/yazi-fm/src/lives/file.rs b/yazi-fm/src/lives/file.rs index 5beba057..c8fafa4f 100644 --- a/yazi-fm/src/lives/file.rs +++ b/yazi-fm/src/lives/file.rs @@ -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() }); @@ -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); } @@ -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::("cx")?; @@ -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 { diff --git a/yazi-fm/src/lives/folder.rs b/yazi-fm/src/lives/folder.rs index bbe3f8f5..8d1e06e3 100644 --- a/yazi-fm/src/lives/folder.rs +++ b/yazi-fm/src/lives/folder.rs @@ -38,7 +38,7 @@ impl Folder { pub(super) fn register(lua: &Lua) -> mlua::Result<()> { lua.register_userdata_type::(|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())); diff --git a/yazi-fm/src/lives/tab.rs b/yazi-fm/src/lives/tab.rs index df622d01..ebdf56f1 100644 --- a/yazi-fm/src/lives/tab.rs +++ b/yazi-fm/src/lives/tab.rs @@ -24,15 +24,7 @@ impl Tab { pub(super) fn register(lua: &Lua) -> mlua::Result<()> { lua.register_userdata_type::(|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)); diff --git a/yazi-fs/src/files.rs b/yazi-fs/src/files.rs index 066ff7d7..135d9f27 100644 --- a/yazi-fs/src/files.rs +++ b/yazi-fs/src/files.rs @@ -55,13 +55,10 @@ impl Files { _ = tx.closed() => break, result = item.metadata() => { let url = Url::from(item.path()); - let file = match result { + _ = tx.send(match result { Ok(meta) => File::from_meta(url, meta).await, Err(_) => File::from_dummy(url, item.file_type().await.ok()) - }; - if let Ok(f) = file { - _ = tx.send(f); - } + }); } } } @@ -82,13 +79,10 @@ impl Files { let mut files = Vec::with_capacity(entries.len() / 3 + 1); for entry in entries { let url = Url::from(entry.path()); - let file = match entry.metadata().await { + files.push(match entry.metadata().await { Ok(meta) => File::from_meta(url, meta).await, Err(_) => File::from_dummy(url, entry.file_type().await.ok()), - }; - if let Ok(f) = file { - files.push(f); - } + }); } files } diff --git a/yazi-fs/src/folder.rs b/yazi-fs/src/folder.rs index f521e179..8ddaf272 100644 --- a/yazi-fs/src/folder.rs +++ b/yazi-fs/src/folder.rs @@ -2,14 +2,14 @@ use std::mem; use yazi_config::{LAYOUT, MANAGER}; use yazi_proxy::ManagerProxy; -use yazi_shared::fs::{Cha, File, FilesOp, Url}; +use yazi_shared::fs::{Cha, File, FilesOp, Loc, Url}; use super::FolderStage; use crate::{Files, Step}; #[derive(Default)] pub struct Folder { - pub cwd: Url, + pub loc: Loc, pub cha: Cha, pub files: Files, pub stage: FolderStage, @@ -22,7 +22,7 @@ pub struct Folder { } impl From<&Url> for Folder { - fn from(cwd: &Url) -> Self { Self { cwd: cwd.clone(), ..Default::default() } } + fn from(cwd: &Url) -> Self { Self { loc: Loc::from(cwd.clone()), ..Default::default() } } } impl Folder { @@ -101,7 +101,7 @@ impl Folder { let new = self.cursor / limit; if mem::replace(&mut self.page, new) != new || force { - ManagerProxy::update_paged_by(new, &self.cwd); + ManagerProxy::update_paged_by(new, &self.loc); } } diff --git a/yazi-plugin/preset/compat.lua b/yazi-plugin/preset/compat.lua index bc76fcc9..4ba28051 100644 --- a/yazi-plugin/preset/compat.lua +++ b/yazi-plugin/preset/compat.lua @@ -1,46 +1 @@ --- TODO: remove this after 0.3.0 release - -Manager = {} -Folder = {} -File = {} - -local function warn(name) - ya.notify { - title = "Deprecated API", - content = string.format( - [[The `%s` global variable has been removed in Yazi v0.3, please remove it from your `init.lua`. - -See https://github.com/sxyazi/yazi/pull/1257 for details.]], - name - ), - timeout = 20, - level = "warn", - } -end - -local b1, b2, b3 = false, false, false -function __yazi_check_and_warn_deprecated_api() - if not b1 then - for _ in pairs(Manager) do - b1 = true - warn("Manager") - break - end - end - - if not b2 then - for _ in pairs(Folder) do - b2 = true - warn("Folder") - break - end - end - - if not b3 then - for _ in pairs(File) do - b3 = true - warn("File") - break - end - end -end +-- diff --git a/yazi-plugin/preset/components/root.lua b/yazi-plugin/preset/components/root.lua index 555bb2b7..61fc6cd0 100644 --- a/yazi-plugin/preset/components/root.lua +++ b/yazi-plugin/preset/components/root.lua @@ -34,7 +34,6 @@ function Root:render() for _, child in ipairs(self._children) do children = ya.list_merge(children, ya.render_with(child)) end - __yazi_check_and_warn_deprecated_api() -- TODO: remove this after 0.3.0 release return children end diff --git a/yazi-plugin/src/file/file.rs b/yazi-plugin/src/file/file.rs index 877aab3f..ae71b755 100644 --- a/yazi-plugin/src/file/file.rs +++ b/yazi-plugin/src/file/file.rs @@ -1,5 +1,6 @@ use mlua::{AnyUserData, Lua, Table, UserDataFields, UserDataMethods, UserDataRef, UserDataRegistry}; use yazi_config::THEME; +use yazi_shared::fs::Loc; use crate::{bindings::{Cast, Icon}, cha::Cha, url::Url}; @@ -48,14 +49,11 @@ impl File { lua.globals().raw_set( "File", lua.create_function(|lua, t: Table| { - // FIXME - todo!(); - Ok(()) - // Self::cast(lua, yazi_shared::fs::File { - // cha: t.raw_get::<_, AnyUserData>("cha")?.take()?, - // url: t.raw_get::<_, AnyUserData>("url")?.take()?, - // ..Default::default() - // }) + Self::cast(lua, yazi_shared::fs::File { + loc: Loc::from(t.raw_get::<_, AnyUserData>("url")?.take()?), + cha: t.raw_get::<_, AnyUserData>("cha")?.take()?, + ..Default::default() + }) })?, ) } diff --git a/yazi-plugin/src/fs/fs.rs b/yazi-plugin/src/fs/fs.rs index 5f9dd036..13e5fb3d 100644 --- a/yazi-plugin/src/fs/fs.rs +++ b/yazi-plugin/src/fs/fs.rs @@ -97,10 +97,7 @@ pub fn install(lua: &Lua) -> mlua::Result<()> { } else { yazi_shared::fs::File::from_dummy(url, next.file_type().await.ok()) }; - - if let Ok(f) = file { - files.push(File::cast(lua, f)?); - } + files.push(File::cast(lua, file)?); } let tbl = lua.create_table_with_capacity(files.len(), 0)?; diff --git a/yazi-shared/src/fs/file.rs b/yazi-shared/src/fs/file.rs index 6ed06d33..e8780f5c 100644 --- a/yazi-shared/src/fs/file.rs +++ b/yazi-shared/src/fs/file.rs @@ -1,15 +1,15 @@ -use std::{cell::Cell, ffi::OsStr, fs::{FileType, Metadata}, ops::Deref}; +use std::{cell::Cell, ffi::OsStr, fs::{FileType, Metadata}, ops::Deref, path::Path}; use anyhow::Result; use tokio::fs; -use super::Location; +use super::Loc; use crate::{fs::{Cha, ChaKind, Url}, theme::IconCache}; #[derive(Clone, Debug, Default)] pub struct File { + pub loc: Loc, pub cha: Cha, - location: Location, pub link_to: Option, pub icon: Cell, } @@ -30,32 +30,42 @@ impl File { #[inline] pub async fn from(url: Url) -> Result { let meta = fs::symlink_metadata(&url).await?; - Self::from_meta(url, meta).await - } - - #[inline] - pub async fn from_meta(url: Url, meta: Metadata) -> Result { - Self::from_loc(Location::from(url)?, meta).await - } - - #[inline] - pub fn from_dummy(url: Url, ft: Option) -> Result { - Ok(Self { - cha: ft.map_or_else(Cha::dummy, Cha::from), - location: Location::from(url)?, - link_to: None, - icon: Default::default(), - }) + Ok(Self::from_meta(url, meta).await) } #[inline] pub async fn from_search(cwd: &Url, url: Url) -> Result { - let loc = Location::from_search(cwd, url)?; + let loc = Loc::from_search(cwd, url); let meta = fs::symlink_metadata(loc.url()).await?; - Self::from_loc(loc, meta).await + Ok(Self::from_loc(loc, meta).await) } - async fn from_loc(loc: Location, mut meta: Metadata) -> Result { + #[inline] + pub async fn from_meta(url: Url, meta: Metadata) -> Self { + Self::from_loc(Loc::from(url), meta).await + } + + #[inline] + pub fn from_dummy(url: Url, ft: Option) -> Self { + Self { + loc: Loc::from(url), + cha: ft.map_or_else(Cha::dummy, Cha::from), + link_to: None, + icon: Default::default(), + } + } + + #[inline] + pub fn rebase(&self, parent: &Url) -> Self { + Self { + loc: self.loc.rebase(parent), + cha: self.cha, + link_to: self.link_to.clone(), + icon: Default::default(), + } + } + + async fn from_loc(loc: Loc, mut meta: Metadata) -> Self { let mut ck = ChaKind::empty(); let (is_link, mut link_to) = (meta.is_symlink(), None); @@ -82,25 +92,23 @@ impl File { } } - Ok(Self { - cha: Cha::from(meta).with_kind(ck), - location: loc, - link_to, - icon: Default::default(), - }) + Self { loc, cha: Cha::from(meta).with_kind(ck), link_to, icon: Default::default() } } } impl File { - // --- Location + // --- Loc #[inline] - pub fn url(&self) -> &Url { self.location.url() } + pub fn url(&self) -> &Url { self.loc.url() } #[inline] pub fn url_owned(&self) -> Url { self.url().clone() } #[inline] - pub fn name(&self) -> &OsStr { self.location.name() } + pub fn urn(&self) -> &Path { self.loc.urn() } + + #[inline] + pub fn name(&self) -> &OsStr { self.loc.name() } #[inline] pub fn stem(&self) -> Option<&OsStr> { self.url().file_stem() } diff --git a/yazi-shared/src/fs/loc.rs b/yazi-shared/src/fs/loc.rs new file mode 100644 index 00000000..9e9e36e1 --- /dev/null +++ b/yazi-shared/src/fs/loc.rs @@ -0,0 +1,96 @@ +use std::{ffi::OsStr, fmt::{self, Debug, Formatter}, ops::Deref, path::Path}; + +use super::Url; + +pub struct Loc { + url: Url, + urn: *const OsStr, + name: *const OsStr, +} + +unsafe impl Send for Loc {} + +impl Default for Loc { + fn default() -> Self { Self { url: Url::default(), urn: OsStr::new(""), name: OsStr::new("") } } +} + +impl Deref for Loc { + type Target = Url; + + fn deref(&self) -> &Self::Target { &self.url } +} + +impl AsRef for Loc { + fn as_ref(&self) -> &Path { self.url() } +} + +impl Eq for Loc {} + +impl PartialEq for Loc { + fn eq(&self, other: &Self) -> bool { + self.url == other.url && self.urn() == other.urn() && self.name() == other.name() + } +} + +impl Clone for Loc { + fn clone(&self) -> Self { + let url = self.url.clone(); + let name = url.file_name().unwrap_or(OsStr::new("")) as *const OsStr; + let urn = if url.is_search() { self.twin_urn(&url) } else { name }; + Self { url, urn, name } + } +} + +impl Debug for Loc { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + f.debug_struct("Loc") + .field("url", &self.url) + .field("urn", &self.urn()) + .field("name", &self.name()) + .finish() + } +} + +impl Loc { + pub fn from(url: Url) -> Self { + let urn = url.file_name().unwrap_or(OsStr::new("")) as *const OsStr; + Self { url, urn, name: urn } + } + + pub fn from_search(cwd: &Url, url: Url) -> Self { + let urn = url.strip_prefix(cwd).unwrap_or(&url).as_os_str() as *const OsStr; + let name = url.file_name().unwrap_or(OsStr::new("")) as *const OsStr; + Self { url, urn, name } + } + + pub fn rebase(&self, parent: &Url) -> Self { + let url = parent.join(self.name()); + let name = url.file_name().unwrap_or(OsStr::new("")) as *const OsStr; + let urn = if url.is_search() { self.twin_urn(&url) } else { name }; + Self { url, urn, name } + } + + #[inline] + fn twin_urn<'a>(&self, new: &'a Url) -> &'a OsStr { + let total = new.components().count(); + let take = self.urn().components().count(); + + let mut it = new.components(); + for _ in 0..total - take { + it.next().unwrap(); + } + + it.as_path().as_os_str() + } +} + +impl Loc { + #[inline] + pub fn url(&self) -> &Url { &self.url } + + #[inline] + pub fn urn(&self) -> &Path { Path::new(unsafe { &*self.urn }) } + + #[inline] + pub fn name(&self) -> &OsStr { unsafe { &*self.name } } +} diff --git a/yazi-shared/src/fs/location.rs b/yazi-shared/src/fs/location.rs deleted file mode 100644 index 804afcc1..00000000 --- a/yazi-shared/src/fs/location.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::{ffi::OsStr, path::Path}; - -use anyhow::{bail, Result}; - -use super::Url; - -#[derive(Clone, Debug)] -pub(super) struct Location { - url: Url, - urn: *const OsStr, - name: *const OsStr, -} - -unsafe impl Send for Location {} - -impl Default for Location { - fn default() -> Self { - let url = Url::default(); - let urn = url.as_os_str() as *const OsStr; - let name = url.as_os_str() as *const OsStr; - Self { url, urn, name } - } -} - -impl Location { - pub(super) fn from(url: Url) -> Result { - if url.is_search() { - bail!("url is from search results: {url:?}"); - } - let Some(name) = url.file_name() else { - bail!("url has no filename: {url:?}"); - }; - - let urn = name as *const OsStr; - let name = name as *const OsStr; - Ok(Self { url, urn, name }) - } - - pub(super) fn from_search(cwd: &Url, url: Url) -> Result { - if !url.is_search() { - bail!("url is not from search results: {url:?}"); - } - let Some(name) = url.file_name() else { - bail!("url has no filename: {url:?}"); - }; - - let urn = url.strip_prefix(cwd).unwrap_or(&url).as_os_str() as *const OsStr; - let name = name as *const OsStr; - Ok(Self { url, urn, name }) - } -} - -impl Location { - #[inline] - pub(super) fn url(&self) -> &Url { &self.url } - - #[inline] - pub(super) fn urn(&self) -> &Path { Path::new(unsafe { &*self.urn }) } - - #[inline] - pub(super) fn name(&self) -> &OsStr { unsafe { &*self.name } } -} diff --git a/yazi-shared/src/fs/mod.rs b/yazi-shared/src/fs/mod.rs index 022ca043..059abbb8 100644 --- a/yazi-shared/src/fs/mod.rs +++ b/yazi-shared/src/fs/mod.rs @@ -1,7 +1,7 @@ mod cha; mod file; mod fns; -mod location; +mod loc; mod op; mod path; mod url; @@ -9,7 +9,7 @@ mod url; pub use cha::*; pub use file::*; pub use fns::*; -pub use location::*; +pub use loc::*; pub use op::*; pub use path::*; pub use url::*; diff --git a/yazi-shared/src/fs/op.rs b/yazi-shared/src/fs/op.rs index 3a0d9803..32338506 100644 --- a/yazi-shared/src/fs/op.rs +++ b/yazi-shared/src/fs/op.rs @@ -48,51 +48,28 @@ impl FilesOp { } pub fn chroot(&self, new: &Url) -> Self { - let old = self.url(); macro_rules! new { - ($url:expr) => {{ new.join($url.strip_prefix(old).unwrap()) }}; + ($url:expr) => {{ new.join($url.file_name().unwrap()) }}; } macro_rules! files { - ($files:expr) => {{ - $files - .iter() - .map(|file| { - let mut f = file.clone(); - // FIXME - todo!(); - // f.url = new!(f.url); - f - }) - .collect() - }}; + ($files:expr) => {{ $files.iter().map(|f| f.rebase(new)).collect() }}; } macro_rules! map { - ($map:expr) => {{ - $map - .iter() - .map(|(k, v)| { - let mut f = v.clone(); - // FIXME - todo!(); - // f.url = new!(f.url); - (new!(k), f) - }) - .collect() - }}; + ($map:expr) => {{ $map.iter().map(|(u, f)| (new!(u), f.rebase(new))).collect() }}; } - let u = new.clone(); + let n = new.clone(); match self { - Self::Full(_, files, mtime) => Self::Full(u, files!(files), *mtime), - Self::Part(_, files, ticket) => Self::Part(u, files!(files), *ticket), - Self::Done(_, mtime, ticket) => Self::Done(u, *mtime, *ticket), - Self::Size(_, map) => Self::Size(u, map.iter().map(|(k, v)| (new!(k), *v)).collect()), - Self::IOErr(_, err) => Self::IOErr(u, *err), + Self::Full(_, files, mtime) => Self::Full(n, files!(files), *mtime), + Self::Part(_, files, ticket) => Self::Part(n, files!(files), *ticket), + Self::Done(_, mtime, ticket) => Self::Done(n, *mtime, *ticket), + Self::Size(_, map) => Self::Size(n, map.iter().map(|(u, &s)| (new!(u), s)).collect()), + Self::IOErr(_, err) => Self::IOErr(n, *err), - Self::Creating(_, files) => Self::Creating(u, files!(files)), - Self::Deleting(_, urls) => Self::Deleting(u, urls.iter().map(|u| new!(u)).collect()), - Self::Updating(_, map) => Self::Updating(u, map!(map)), - Self::Upserting(_, map) => Self::Upserting(u, map!(map)), + Self::Creating(_, files) => Self::Creating(n, files!(files)), + Self::Deleting(_, urls) => Self::Deleting(n, urls.iter().map(|u| new!(u)).collect()), + Self::Updating(_, map) => Self::Updating(n, map!(map)), + Self::Upserting(_, map) => Self::Upserting(n, map!(map)), } } } diff --git a/yazi-shared/src/fs/url.rs b/yazi-shared/src/fs/url.rs index 2d8c506a..16574c21 100644 --- a/yazi-shared/src/fs/url.rs +++ b/yazi-shared/src/fs/url.rs @@ -128,7 +128,7 @@ impl Url { let url = Self::from(self.path.join(path)); match self.scheme { UrlScheme::Regular => url, - UrlScheme::Search => url, + UrlScheme::Search => url.into_search(), UrlScheme::Archive => url.into_archive(), } } @@ -161,12 +161,14 @@ impl Url { } impl Url { - // --- Scheme + // --- Regular #[inline] pub fn is_regular(&self) -> bool { self.scheme == UrlScheme::Regular } #[inline] - pub fn to_regular(&self) -> Self { self.clone().into_regular() } + pub fn to_regular(&self) -> Self { + Self { scheme: UrlScheme::Regular, path: self.path.clone(), frag: String::new() } + } #[inline] pub fn into_regular(mut self) -> Self { @@ -175,16 +177,19 @@ impl Url { self } + // --- Search #[inline] pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search } #[inline] - pub fn to_search(&self, frag: &str) -> Self { self.clone().into_search(frag) } + pub fn to_search(&self, frag: &str) -> Self { + Self { scheme: UrlScheme::Search, path: self.path.clone(), frag: frag.to_owned() } + } #[inline] - pub fn into_search(mut self, frag: &str) -> Self { + pub fn into_search(mut self) -> Self { self.scheme = UrlScheme::Search; - self.frag = frag.to_owned(); + self.frag = String::new(); self } @@ -192,7 +197,9 @@ impl Url { pub fn is_archive(&self) -> bool { self.scheme == UrlScheme::Archive } #[inline] - pub fn to_archive(&self) -> Self { self.clone().into_archive() } + pub fn to_archive(&self) -> Self { + Self { scheme: UrlScheme::Archive, path: self.path.clone(), frag: String::new() } + } #[inline] pub fn into_archive(mut self) -> Self {