This commit is contained in:
sxyazi 2024-09-10 00:29:43 +08:00
parent fe2af1025d
commit 7da764e1f6
No known key found for this signature in database
32 changed files with 256 additions and 269 deletions

View file

@ -82,7 +82,6 @@ impl Ueberzug {
} }
fn create_demon(adapter: Adapter) -> Result<Child> { fn create_demon(adapter: Adapter) -> Result<Child> {
// TODO: demon
let result = Command::new("ueberzugpp") let result = Command::new("ueberzugpp")
.args(["layer", "-so", &adapter.to_string()]) .args(["layer", "-so", &adapter.to_string()])
.env("SPDLOG_LEVEL", if cfg!(debug_assertions) { "debug" } else { "" }) .env("SPDLOG_LEVEL", if cfg!(debug_assertions) { "debug" } else { "" })

View file

@ -40,9 +40,9 @@ impl Manager {
// Refresh watcher // Refresh watcher
let mut to_watch = HashSet::with_capacity(3 * self.tabs.len()); let mut to_watch = HashSet::with_capacity(3 * self.tabs.len());
for tab in self.tabs.iter() { for tab in self.tabs.iter() {
to_watch.insert(&tab.current.cwd); to_watch.insert(tab.cwd());
if let Some(ref p) = tab.parent { 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()) { if let Some(h) = tab.current.hovered().filter(|&h| h.is_dir()) {
to_watch.insert(h.url()); to_watch.insert(h.url());

View file

@ -111,7 +111,7 @@ impl Manager {
let find = |folder: Option<&Folder>| { let find = |folder: Option<&Folder>| {
folder.is_some_and(|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())
}) })
}; };

View file

@ -46,7 +46,7 @@ impl Tabs {
} else { } else {
tab.conf = self.active().conf.clone(); tab.conf = self.active().conf.clone();
tab.apply_files_attrs(); tab.apply_files_attrs();
tab.cd(self.active().current.cwd.clone()); tab.cd(self.active().cwd().clone());
} }
self.items.insert(self.cursor + 1, tab); self.items.insert(self.cursor + 1, tab);

View file

@ -47,9 +47,9 @@ impl Manager {
let url = op.url(); let url = op.url();
tab.selected.apply_op(&op); tab.selected.apply_op(&op);
if tab.current.cwd == *url { if url == tab.cwd() {
Self::update_current(tab, op, tasks); 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); Self::update_parent(tab, op);
} else if matches!(tab.current.hovered(), Some(h) if url == h.url()) { } else if matches!(tab.current.hovered(), Some(h) if url == h.url()) {
Self::update_hovered(tab, op); Self::update_hovered(tab, op);
@ -59,7 +59,7 @@ impl Manager {
} }
fn update_parent(tab: &mut Tab, op: Cow<FilesOp>) { 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)); let leave = matches!(*op, FilesOp::Deleting(_, ref urls) if urls.contains(&cwd));
if let Some(f) = tab.parent.as_mut() { if let Some(f) = tab.parent.as_mut() {
@ -108,7 +108,7 @@ impl Manager {
} }
fn update_history(tab: &mut Tab, op: Cow<FilesOp>) { 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)), |(p, pp)| matches!(*op, FilesOp::Deleting(ref parent, ref urls) if *parent == pp && urls.contains(p)),
); );

View file

@ -27,7 +27,7 @@ impl Manager {
return; 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; return;
} }

View file

@ -41,7 +41,7 @@ impl Manager {
impl Manager { impl Manager {
#[inline] #[inline]
pub fn cwd(&self) -> &Url { &self.current().cwd } pub fn cwd(&self) -> &Url { &self.current().loc }
#[inline] #[inline]
pub fn active(&self) -> &Tab { self.tabs.active() } pub fn active(&self) -> &Tab { self.tabs.active() }

View file

@ -60,8 +60,11 @@ impl Watcher {
} }
pub(super) fn trigger_dirs(&self, folders: &[&Folder]) { pub(super) fn trigger_dirs(&self, folders: &[&Folder]) {
let todo: Vec<_> = let todo: Vec<_> = folders
folders.iter().filter(|&f| f.cwd.is_regular()).map(|&f| (f.cwd.clone(), f.cha)).collect(); .iter()
.filter(|&f| f.loc.is_regular())
.map(|&f| (f.loc.url().clone(), f.cha))
.collect();
if todo.is_empty() { if todo.is_empty() {
return; return;
} }

View file

@ -39,25 +39,25 @@ impl Tab {
return self.cd_interactive(); return self.cd_interactive();
} }
if self.current.cwd == opt.target { if opt.target == *self.cwd() {
return; return;
} }
// Take parent to history // Take parent to history
if let Some(rep) = self.parent.take() { if let Some(rep) = self.parent.take() {
self.history.insert(rep.cwd.clone(), rep); self.history.insert(rep.loc.url().clone(), rep);
} }
// Current // Current
let rep = self.history_new(&opt.target); let rep = self.history.remove_or(&opt.target);
let rep = mem::replace(&mut self.current, rep); let rep = mem::replace(&mut self.current, rep);
if rep.cwd.is_regular() { if rep.loc.is_regular() {
self.history.insert(rep.cwd.clone(), rep); self.history.insert(rep.loc.url().clone(), rep);
} }
// Parent // Parent
if let Some(parent) = opt.target.parent_url() { if let Some(parent) = opt.target.parent_url() {
self.parent = Some(self.history_new(&parent)); self.parent = Some(self.history.remove_or(&parent));
} }
// Backstack // Backstack
@ -65,7 +65,7 @@ impl Tab {
self.backstack.push(opt.target.clone()); 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(); ManagerProxy::refresh();
render!(); render!();
} }

View file

@ -92,7 +92,7 @@ impl Tab {
} }
pub fn escape_search(&mut self) -> bool { pub fn escape_search(&mut self) -> bool {
let b = self.current.cwd.is_search(); let b = self.cwd().is_search();
self.search_stop(); self.search_stop();
render_and!(b) render_and!(b)
@ -108,7 +108,7 @@ impl Tab {
let urls: Vec<_> = let urls: Vec<_> =
indices.into_iter().filter_map(|i| self.current.files.get(i)).map(|f| f.url()).collect(); 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 { if !select {
self.selected.remove_many(&urls, same); self.selected.remove_many(&urls, same);
} else if self.selected.add_many(&urls, same) != urls.len() { } else if self.selected.add_many(&urls, same) != urls.len() {

View file

@ -16,8 +16,8 @@ impl Tab {
.current .current
.hovered() .hovered()
.and_then(|h| h.parent()) .and_then(|h| h.parent())
.filter(|p| *p != self.current.cwd) .filter(|p| p != self.cwd())
.or_else(|| self.current.cwd.parent_url()) .or_else(|| self.cwd().parent_url())
.map(|u| self.cd(u)); .map(|u| self.cd(u));
} }
} }

View file

@ -28,12 +28,9 @@ impl Tab {
let Some(parent) = opt.target.parent_url() else { let Some(parent) = opt.target.parent_url() else {
return; return;
}; };
let Ok(file) = File::from_dummy(opt.target.clone(), None) else {
return;
};
self.cd(parent.clone()); 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); ManagerProxy::hover(Some(opt.target), self.idx);
} }
} }

View file

@ -44,7 +44,7 @@ impl Tab {
handle.abort(); 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; let hidden = self.conf.show_hidden;
self.search = Some(tokio::spawn(async move { self.search = Some(tokio::spawn(async move {
@ -81,8 +81,8 @@ impl Tab {
if let Some(handle) = self.search.take() { if let Some(handle) = self.search.take() {
handle.abort(); handle.abort();
} }
if self.current.cwd.is_search() { if self.cwd().is_search() {
let rep = self.history_new(&self.current.cwd.to_regular()); let rep = self.history.remove_or(&self.cwd().to_regular());
drop(mem::replace(&mut self.current, rep)); drop(mem::replace(&mut self.current, rep));
ManagerProxy::refresh(); ManagerProxy::refresh();
} }

View file

@ -31,7 +31,7 @@ impl Tab {
None => iter.partition(|&u| self.selected.contains_key(u)), 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); render!(self.selected.remove_many(&removal, same) > 0);
let added = self.selected.add_many(&addition, same); let added = self.selected.add_many(&addition, same);

View file

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

View file

@ -2,6 +2,7 @@ mod backstack;
mod commands; mod commands;
mod config; mod config;
mod finder; mod finder;
mod history;
mod mode; mod mode;
mod preview; mod preview;
mod selected; mod selected;
@ -10,6 +11,7 @@ mod tab;
pub use backstack::*; pub use backstack::*;
pub use config::*; pub use config::*;
pub use finder::*; pub use finder::*;
pub use history::*;
pub use mode::*; pub use mode::*;
pub use preview::*; pub use preview::*;
pub use selected::*; pub use selected::*;

View file

@ -1,4 +1,4 @@
use std::{collections::HashMap, iter}; use std::iter;
use anyhow::Result; use anyhow::Result;
use ratatui::layout::Rect; use ratatui::layout::Rect;
@ -8,7 +8,7 @@ use yazi_config::{popup::{Origin, Position}, LAYOUT};
use yazi_fs::{Folder, FolderStage}; use yazi_fs::{Folder, FolderStage};
use yazi_shared::{fs::Url, render}; 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; use crate::tab::Selected;
#[derive(Default)] #[derive(Default)]
@ -20,7 +20,7 @@ pub struct Tab {
pub parent: Option<Folder>, pub parent: Option<Folder>,
pub backstack: Backstack<Url>, pub backstack: Backstack<Url>,
pub history: HashMap<Url, Folder>, pub history: History,
pub selected: Selected, pub selected: Selected,
pub preview: Preview, pub preview: Preview,
@ -38,6 +38,9 @@ impl Tab {
impl Tab { impl Tab {
// --- Current // --- Current
#[inline]
pub fn cwd(&self) -> &Url { &self.current.loc }
pub fn hovered_rect(&self) -> Option<Rect> { pub fn hovered_rect(&self) -> Option<Rect> {
let y = self.current.files.position(self.current.hovered()?.url())? - self.current.offset; let y = self.current.files.position(self.current.hovered()?.url())? - self.current.offset;
@ -83,10 +86,6 @@ impl Tab {
} }
// --- History // --- History
#[inline]
pub fn history_new(&mut self, url: &Url) -> Folder {
self.history.remove(url).unwrap_or_else(|| Folder::from(url))
}
#[inline] #[inline]
pub fn hovered_folder(&self) -> Option<&Folder> { pub fn hovered_folder(&self) -> Option<&Folder> {
@ -113,8 +112,8 @@ impl Tab {
apply(parent); apply(parent);
// The parent should always track the CWD // The parent should always track the CWD
parent.hover(&self.current.cwd); parent.hover(&self.current.loc);
parent.tracing = parent.hovered().map(|h| h.url()) == Some(&self.current.cwd); parent.tracing = parent.hovered().map(|h| h.url()) == Some(&self.current.loc);
} }
self self

View file

@ -46,11 +46,11 @@ impl File {
Ok(cx.manager.mimetype.get(me.url()).cloned()) Ok(cx.manager.mimetype.get(me.url()).cloned())
}); });
reg.add_method("prefix", |lua, me, ()| { reg.add_method("prefix", |lua, me, ()| {
if !me.folder().cwd.is_search() { if !me.folder().loc.is_search() {
return Ok(None); 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(); p.next_back();
Some(lua.create_string(p.as_path().as_os_str().as_encoded_bytes())).transpose() 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, ()| { reg.add_method("is_marked", |_, me, ()| {
use yazi_core::tab::Mode::*; 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); 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("is_selected", |_, me, ()| Ok(me.tab().selected.contains_key(me.url())));
reg.add_method("in_parent", |_, me, ()| { 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, ()| { 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, ()| { reg.add_method("found", |lua, me, ()| {
let cx = lua.named_registry_value::<CtxRef>("cx")?; let cx = lua.named_registry_value::<CtxRef>("cx")?;
@ -113,7 +113,7 @@ impl File {
let Some(finder) = &cx.manager.active().finder else { let Some(finder) = &cx.manager.active().finder else {
return Ok(None); return Ok(None);
}; };
if me.folder().cwd != me.tab().current.cwd { if me.folder().loc != me.tab().current.loc {
return Ok(None); return Ok(None);
} }
let Some(h) = finder.filter.highlighted(me.name()) else { let Some(h) = finder.filter.highlighted(me.name()) else {

View file

@ -38,7 +38,7 @@ impl Folder {
pub(super) fn register(lua: &Lua) -> mlua::Result<()> { pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<Self>(|reg| { 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("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("stage", |lua, me| lua.create_any_userdata(me.stage));
reg.add_field_method_get("window", |_, me| Files::make(me.window.clone(), me, me.tab())); reg.add_field_method_get("window", |_, me| Files::make(me.window.clone(), me, me.tab()));

View file

@ -24,15 +24,7 @@ impl Tab {
pub(super) fn register(lua: &Lua) -> mlua::Result<()> { pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
lua.register_userdata_type::<Self>(|reg| { lua.register_userdata_type::<Self>(|reg| {
reg.add_method("name", |lua, me, ()| { reg.add_method("name", |lua, me, ()| {
Some( Some(lua.create_string(me.current.loc.name().as_encoded_bytes())).transpose()
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()
}); });
reg.add_field_method_get("mode", |_, me| Mode::make(&me.mode)); reg.add_field_method_get("mode", |_, me| Mode::make(&me.mode));

View file

@ -55,13 +55,10 @@ impl Files {
_ = tx.closed() => break, _ = tx.closed() => break,
result = item.metadata() => { result = item.metadata() => {
let url = Url::from(item.path()); let url = Url::from(item.path());
let file = match result { _ = tx.send(match result {
Ok(meta) => File::from_meta(url, meta).await, Ok(meta) => File::from_meta(url, meta).await,
Err(_) => File::from_dummy(url, item.file_type().await.ok()) 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); let mut files = Vec::with_capacity(entries.len() / 3 + 1);
for entry in entries { for entry in entries {
let url = Url::from(entry.path()); 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, Ok(meta) => File::from_meta(url, meta).await,
Err(_) => File::from_dummy(url, entry.file_type().await.ok()), Err(_) => File::from_dummy(url, entry.file_type().await.ok()),
}; });
if let Ok(f) = file {
files.push(f);
}
} }
files files
} }

View file

@ -2,14 +2,14 @@ use std::mem;
use yazi_config::{LAYOUT, MANAGER}; use yazi_config::{LAYOUT, MANAGER};
use yazi_proxy::ManagerProxy; 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 super::FolderStage;
use crate::{Files, Step}; use crate::{Files, Step};
#[derive(Default)] #[derive(Default)]
pub struct Folder { pub struct Folder {
pub cwd: Url, pub loc: Loc,
pub cha: Cha, pub cha: Cha,
pub files: Files, pub files: Files,
pub stage: FolderStage, pub stage: FolderStage,
@ -22,7 +22,7 @@ pub struct Folder {
} }
impl From<&Url> for 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 { impl Folder {
@ -101,7 +101,7 @@ impl Folder {
let new = self.cursor / limit; let new = self.cursor / limit;
if mem::replace(&mut self.page, new) != new || force { if mem::replace(&mut self.page, new) != new || force {
ManagerProxy::update_paged_by(new, &self.cwd); ManagerProxy::update_paged_by(new, &self.loc);
} }
} }

View file

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

View file

@ -34,7 +34,6 @@ function Root:render()
for _, child in ipairs(self._children) do for _, child in ipairs(self._children) do
children = ya.list_merge(children, ya.render_with(child)) children = ya.list_merge(children, ya.render_with(child))
end end
__yazi_check_and_warn_deprecated_api() -- TODO: remove this after 0.3.0 release
return children return children
end end

View file

@ -1,5 +1,6 @@
use mlua::{AnyUserData, Lua, Table, UserDataFields, UserDataMethods, UserDataRef, UserDataRegistry}; use mlua::{AnyUserData, Lua, Table, UserDataFields, UserDataMethods, UserDataRef, UserDataRegistry};
use yazi_config::THEME; use yazi_config::THEME;
use yazi_shared::fs::Loc;
use crate::{bindings::{Cast, Icon}, cha::Cha, url::Url}; use crate::{bindings::{Cast, Icon}, cha::Cha, url::Url};
@ -48,14 +49,11 @@ impl File {
lua.globals().raw_set( lua.globals().raw_set(
"File", "File",
lua.create_function(|lua, t: Table| { lua.create_function(|lua, t: Table| {
// FIXME Self::cast(lua, yazi_shared::fs::File {
todo!(); loc: Loc::from(t.raw_get::<_, AnyUserData>("url")?.take()?),
Ok(()) cha: t.raw_get::<_, AnyUserData>("cha")?.take()?,
// Self::cast(lua, yazi_shared::fs::File { ..Default::default()
// cha: t.raw_get::<_, AnyUserData>("cha")?.take()?, })
// url: t.raw_get::<_, AnyUserData>("url")?.take()?,
// ..Default::default()
// })
})?, })?,
) )
} }

View file

@ -97,10 +97,7 @@ pub fn install(lua: &Lua) -> mlua::Result<()> {
} else { } else {
yazi_shared::fs::File::from_dummy(url, next.file_type().await.ok()) yazi_shared::fs::File::from_dummy(url, next.file_type().await.ok())
}; };
files.push(File::cast(lua, file)?);
if let Ok(f) = file {
files.push(File::cast(lua, f)?);
}
} }
let tbl = lua.create_table_with_capacity(files.len(), 0)?; let tbl = lua.create_table_with_capacity(files.len(), 0)?;

View file

@ -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 anyhow::Result;
use tokio::fs; use tokio::fs;
use super::Location; use super::Loc;
use crate::{fs::{Cha, ChaKind, Url}, theme::IconCache}; use crate::{fs::{Cha, ChaKind, Url}, theme::IconCache};
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct File { pub struct File {
pub loc: Loc,
pub cha: Cha, pub cha: Cha,
location: Location,
pub link_to: Option<Url>, pub link_to: Option<Url>,
pub icon: Cell<IconCache>, pub icon: Cell<IconCache>,
} }
@ -30,32 +30,42 @@ impl File {
#[inline] #[inline]
pub async fn from(url: Url) -> Result<Self> { pub async fn from(url: Url) -> Result<Self> {
let meta = fs::symlink_metadata(&url).await?; let meta = fs::symlink_metadata(&url).await?;
Self::from_meta(url, meta).await Ok(Self::from_meta(url, meta).await)
}
#[inline]
pub async fn from_meta(url: Url, meta: Metadata) -> Result<Self> {
Self::from_loc(Location::from(url)?, meta).await
}
#[inline]
pub fn from_dummy(url: Url, ft: Option<FileType>) -> Result<Self> {
Ok(Self {
cha: ft.map_or_else(Cha::dummy, Cha::from),
location: Location::from(url)?,
link_to: None,
icon: Default::default(),
})
} }
#[inline] #[inline]
pub async fn from_search(cwd: &Url, url: Url) -> Result<Self> { pub async fn from_search(cwd: &Url, url: Url) -> Result<Self> {
let loc = Location::from_search(cwd, url)?; let loc = Loc::from_search(cwd, url);
let meta = fs::symlink_metadata(loc.url()).await?; 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<Self> { #[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<FileType>) -> 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 mut ck = ChaKind::empty();
let (is_link, mut link_to) = (meta.is_symlink(), None); let (is_link, mut link_to) = (meta.is_symlink(), None);
@ -82,25 +92,23 @@ impl File {
} }
} }
Ok(Self { Self { loc, cha: Cha::from(meta).with_kind(ck), link_to, icon: Default::default() }
cha: Cha::from(meta).with_kind(ck),
location: loc,
link_to,
icon: Default::default(),
})
} }
} }
impl File { impl File {
// --- Location // --- Loc
#[inline] #[inline]
pub fn url(&self) -> &Url { self.location.url() } pub fn url(&self) -> &Url { self.loc.url() }
#[inline] #[inline]
pub fn url_owned(&self) -> Url { self.url().clone() } pub fn url_owned(&self) -> Url { self.url().clone() }
#[inline] #[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] #[inline]
pub fn stem(&self) -> Option<&OsStr> { self.url().file_stem() } pub fn stem(&self) -> Option<&OsStr> { self.url().file_stem() }

96
yazi-shared/src/fs/loc.rs Normal file
View file

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

View file

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

View file

@ -1,7 +1,7 @@
mod cha; mod cha;
mod file; mod file;
mod fns; mod fns;
mod location; mod loc;
mod op; mod op;
mod path; mod path;
mod url; mod url;
@ -9,7 +9,7 @@ mod url;
pub use cha::*; pub use cha::*;
pub use file::*; pub use file::*;
pub use fns::*; pub use fns::*;
pub use location::*; pub use loc::*;
pub use op::*; pub use op::*;
pub use path::*; pub use path::*;
pub use url::*; pub use url::*;

View file

@ -48,51 +48,28 @@ impl FilesOp {
} }
pub fn chroot(&self, new: &Url) -> Self { pub fn chroot(&self, new: &Url) -> Self {
let old = self.url();
macro_rules! new { macro_rules! new {
($url:expr) => {{ new.join($url.strip_prefix(old).unwrap()) }}; ($url:expr) => {{ new.join($url.file_name().unwrap()) }};
} }
macro_rules! files { macro_rules! files {
($files:expr) => {{ ($files:expr) => {{ $files.iter().map(|f| f.rebase(new)).collect() }};
$files
.iter()
.map(|file| {
let mut f = file.clone();
// FIXME
todo!();
// f.url = new!(f.url);
f
})
.collect()
}};
} }
macro_rules! map { macro_rules! map {
($map:expr) => {{ ($map:expr) => {{ $map.iter().map(|(u, f)| (new!(u), f.rebase(new))).collect() }};
$map
.iter()
.map(|(k, v)| {
let mut f = v.clone();
// FIXME
todo!();
// f.url = new!(f.url);
(new!(k), f)
})
.collect()
}};
} }
let u = new.clone(); let n = new.clone();
match self { match self {
Self::Full(_, files, mtime) => Self::Full(u, files!(files), *mtime), Self::Full(_, files, mtime) => Self::Full(n, files!(files), *mtime),
Self::Part(_, files, ticket) => Self::Part(u, files!(files), *ticket), Self::Part(_, files, ticket) => Self::Part(n, files!(files), *ticket),
Self::Done(_, mtime, ticket) => Self::Done(u, *mtime, *ticket), Self::Done(_, mtime, ticket) => Self::Done(n, *mtime, *ticket),
Self::Size(_, map) => Self::Size(u, map.iter().map(|(k, v)| (new!(k), *v)).collect()), Self::Size(_, map) => Self::Size(n, map.iter().map(|(u, &s)| (new!(u), s)).collect()),
Self::IOErr(_, err) => Self::IOErr(u, *err), Self::IOErr(_, err) => Self::IOErr(n, *err),
Self::Creating(_, files) => Self::Creating(u, files!(files)), Self::Creating(_, files) => Self::Creating(n, files!(files)),
Self::Deleting(_, urls) => Self::Deleting(u, urls.iter().map(|u| new!(u)).collect()), Self::Deleting(_, urls) => Self::Deleting(n, urls.iter().map(|u| new!(u)).collect()),
Self::Updating(_, map) => Self::Updating(u, map!(map)), Self::Updating(_, map) => Self::Updating(n, map!(map)),
Self::Upserting(_, map) => Self::Upserting(u, map!(map)), Self::Upserting(_, map) => Self::Upserting(n, map!(map)),
} }
} }
} }

View file

@ -128,7 +128,7 @@ impl Url {
let url = Self::from(self.path.join(path)); let url = Self::from(self.path.join(path));
match self.scheme { match self.scheme {
UrlScheme::Regular => url, UrlScheme::Regular => url,
UrlScheme::Search => url, UrlScheme::Search => url.into_search(),
UrlScheme::Archive => url.into_archive(), UrlScheme::Archive => url.into_archive(),
} }
} }
@ -161,12 +161,14 @@ impl Url {
} }
impl Url { impl Url {
// --- Scheme // --- Regular
#[inline] #[inline]
pub fn is_regular(&self) -> bool { self.scheme == UrlScheme::Regular } pub fn is_regular(&self) -> bool { self.scheme == UrlScheme::Regular }
#[inline] #[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] #[inline]
pub fn into_regular(mut self) -> Self { pub fn into_regular(mut self) -> Self {
@ -175,16 +177,19 @@ impl Url {
self self
} }
// --- Search
#[inline] #[inline]
pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search } pub fn is_search(&self) -> bool { self.scheme == UrlScheme::Search }
#[inline] #[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] #[inline]
pub fn into_search(mut self, frag: &str) -> Self { pub fn into_search(mut self) -> Self {
self.scheme = UrlScheme::Search; self.scheme = UrlScheme::Search;
self.frag = frag.to_owned(); self.frag = String::new();
self self
} }
@ -192,7 +197,9 @@ impl Url {
pub fn is_archive(&self) -> bool { self.scheme == UrlScheme::Archive } pub fn is_archive(&self) -> bool { self.scheme == UrlScheme::Archive }
#[inline] #[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] #[inline]
pub fn into_archive(mut self) -> Self { pub fn into_archive(mut self) -> Self {