From e8c1d625acb7d35393b6894d290225b2e6c0cf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Thu, 24 Oct 2024 08:57:08 +0800 Subject: [PATCH] fix: use a unique `Id` for each tab (#1826) --- yazi-core/src/manager/commands/hover.rs | 13 ++--- yazi-core/src/manager/commands/tab_close.rs | 1 - yazi-core/src/manager/commands/tab_create.rs | 4 +- yazi-core/src/manager/commands/tab_swap.rs | 1 - .../src/manager/commands/update_files.rs | 2 +- yazi-core/src/manager/manager.rs | 10 ++-- yazi-core/src/manager/tabs.rs | 18 +++---- yazi-core/src/tab/commands/arrow.rs | 2 +- yazi-core/src/tab/commands/cd.rs | 2 +- yazi-core/src/tab/commands/filter_do.rs | 2 +- yazi-core/src/tab/commands/hidden.rs | 2 +- yazi-core/src/tab/commands/reveal.rs | 2 +- yazi-core/src/tab/tab.rs | 27 ++++++++-- yazi-dds/src/body/cd.rs | 12 ++--- yazi-dds/src/body/hover.rs | 12 ++--- yazi-dds/src/pubsub.rs | 6 +-- yazi-fm/src/lives/tab.rs | 2 +- yazi-fs/src/files.rs | 14 ++--- yazi-plugin/src/external/highlighter.rs | 14 ++--- yazi-proxy/src/manager.rs | 4 +- yazi-shared/src/event/data.rs | 2 + yazi-shared/src/fs/op.rs | 14 ++--- yazi-shared/src/id.rs | 54 +++++++++++++++++++ yazi-shared/src/lib.rs | 5 +- 24 files changed, 143 insertions(+), 82 deletions(-) create mode 100644 yazi-shared/src/id.rs diff --git a/yazi-core/src/manager/commands/hover.rs b/yazi-core/src/manager/commands/hover.rs index 632e41f2..45caad8e 100644 --- a/yazi-core/src/manager/commands/hover.rs +++ b/yazi-core/src/manager/commands/hover.rs @@ -2,21 +2,18 @@ use std::{collections::HashSet, path::PathBuf}; use yazi_dds::Pubsub; use yazi_macro::render; -use yazi_shared::{event::{Cmd, Data}, fs::{Url, Urn}}; +use yazi_shared::{Id, event::{Cmd, Data}, fs::{Url, Urn}}; use crate::manager::Manager; struct Opt { url: Option, - tab: Option, + tab: Option, } impl From for Opt { fn from(mut c: Cmd) -> Self { - Self { - url: c.take_first().and_then(Data::into_url), - tab: c.get("tab").and_then(Data::as_usize), - } + Self { url: c.take_first().and_then(Data::into_url), tab: c.get("tab").and_then(Data::as_id) } } } impl From> for Opt { @@ -49,10 +46,10 @@ impl Manager { self.watcher.watch(to_watch); // Publish through DDS - Pubsub::pub_from_hover(self.active().idx, self.hovered().map(|h| &h.url)); + Pubsub::pub_from_hover(self.active().id, self.hovered().map(|h| &h.url)); } - fn hover_do(&mut self, url: Url, tab: Option) { + fn hover_do(&mut self, url: Url, tab: Option) { // Hover on the file if let Ok(p) = url.strip_prefix(&self.current_or(tab).url).map(PathBuf::from) { render!(self.current_or_mut(tab).repos(Some(Urn::new(&p)))); diff --git a/yazi-core/src/manager/commands/tab_close.rs b/yazi-core/src/manager/commands/tab_close.rs index 47481ee7..3f475ac6 100644 --- a/yazi-core/src/manager/commands/tab_close.rs +++ b/yazi-core/src/manager/commands/tab_close.rs @@ -30,7 +30,6 @@ impl Tabs { self.set_idx(self.absolute(1)); } - self.reorder(); render!(); } } diff --git a/yazi-core/src/manager/commands/tab_create.rs b/yazi-core/src/manager/commands/tab_create.rs index b104aba0..39993e73 100644 --- a/yazi-core/src/manager/commands/tab_create.rs +++ b/yazi-core/src/manager/commands/tab_create.rs @@ -36,8 +36,7 @@ impl Tabs { return; } - let mut tab = Tab { idx: self.cursor + 1, ..Default::default() }; - + let mut tab = Tab::default(); if !opt.current { tab.cd(opt.url); } else if let Some(h) = self.active().hovered() { @@ -52,7 +51,6 @@ impl Tabs { self.items.insert(self.cursor + 1, tab); self.set_idx(self.cursor + 1); - self.reorder(); render!(); } } diff --git a/yazi-core/src/manager/commands/tab_swap.rs b/yazi-core/src/manager/commands/tab_swap.rs index 183f005e..14439744 100644 --- a/yazi-core/src/manager/commands/tab_swap.rs +++ b/yazi-core/src/manager/commands/tab_swap.rs @@ -21,7 +21,6 @@ impl Tabs { self.items.swap(self.cursor, idx); self.set_idx(idx); - self.reorder(); render!(); } } diff --git a/yazi-core/src/manager/commands/update_files.rs b/yazi-core/src/manager/commands/update_files.rs index 2be38e4d..b88abb05 100644 --- a/yazi-core/src/manager/commands/update_files.rs +++ b/yazi-core/src/manager/commands/update_files.rs @@ -87,7 +87,7 @@ impl Manager { return; } - ManagerProxy::hover(None, tab.idx); // Re-hover in next loop + ManagerProxy::hover(None, tab.id); // Re-hover in next loop ManagerProxy::update_paged(); // Update for paged files in next loop if calc { tasks.prework_sorted(&tab.current.files); diff --git a/yazi-core/src/manager/manager.rs b/yazi-core/src/manager/manager.rs index b262fc11..4efd9b27 100644 --- a/yazi-core/src/manager/manager.rs +++ b/yazi-core/src/manager/manager.rs @@ -2,7 +2,7 @@ use ratatui::layout::Rect; use yazi_adapter::Dimension; use yazi_config::popup::{Origin, Position}; use yazi_fs::Folder; -use yazi_shared::fs::{File, Url}; +use yazi_shared::{Id, fs::{File, Url}}; use super::{Mimetype, Tabs, Watcher, Yanked}; use crate::tab::Tab; @@ -48,10 +48,10 @@ impl Manager { pub fn active_mut(&mut self) -> &mut Tab { self.tabs.active_mut() } #[inline] - pub fn active_or(&self, idx: Option) -> &Tab { self.tabs.active_or(idx) } + pub fn active_or(&self, id: Option) -> &Tab { self.tabs.active_or(id) } #[inline] - pub fn active_or_mut(&mut self, idx: Option) -> &mut Tab { self.tabs.active_or_mut(idx) } + pub fn active_or_mut(&mut self, id: Option) -> &mut Tab { self.tabs.active_or_mut(id) } #[inline] pub fn current(&self) -> &Folder { &self.active().current } @@ -60,10 +60,10 @@ impl Manager { pub fn current_mut(&mut self) -> &mut Folder { &mut self.active_mut().current } #[inline] - pub fn current_or(&self, idx: Option) -> &Folder { &self.active_or(idx).current } + pub fn current_or(&self, idx: Option) -> &Folder { &self.active_or(idx).current } #[inline] - pub fn current_or_mut(&mut self, idx: Option) -> &mut Folder { + pub fn current_or_mut(&mut self, idx: Option) -> &mut Folder { &mut self.active_or_mut(idx).current } diff --git a/yazi-core/src/manager/tabs.rs b/yazi-core/src/manager/tabs.rs index 9251c0ef..1dfce8f1 100644 --- a/yazi-core/src/manager/tabs.rs +++ b/yazi-core/src/manager/tabs.rs @@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut}; use yazi_boot::BOOT; use yazi_dds::Pubsub; use yazi_proxy::ManagerProxy; -use yazi_shared::fs::Url; +use yazi_shared::{Id, fs::Url}; use crate::tab::Tab; @@ -16,7 +16,6 @@ impl Tabs { pub fn make() -> Self { let mut tabs = Self { cursor: 0, items: (0..BOOT.cwds.len()).map(|_| Tab::default()).collect() }; - tabs.reorder(); for (i, tab) in tabs.iter_mut().enumerate() { let file = &BOOT.files[i]; @@ -37,11 +36,6 @@ impl Tabs { } } - #[inline] - pub(super) fn reorder(&mut self) { - self.items.iter_mut().enumerate().for_each(|(i, tab)| tab.idx = i); - } - pub(super) fn set_idx(&mut self, idx: usize) { // Reset the preview of the last active tab if let Some(active) = self.items.get_mut(self.cursor) { @@ -63,16 +57,16 @@ impl Tabs { pub(super) fn active_mut(&mut self) -> &mut Tab { &mut self.items[self.cursor] } #[inline] - pub fn active_or(&self, idx: Option) -> &Tab { - idx.and_then(|i| self.items.get(i)).unwrap_or(&self.items[self.cursor]) + pub fn active_or(&self, id: Option) -> &Tab { + id.and_then(|id| self.iter().find(|&t| t.id == id)).unwrap_or(self.active()) } #[inline] - pub(super) fn active_or_mut(&mut self, idx: Option) -> &mut Tab { - if let Some(i) = idx.filter(|&i| i < self.items.len()) { + pub(super) fn active_or_mut(&mut self, id: Option) -> &mut Tab { + if let Some(i) = id.and_then(|id| self.iter().position(|t| t.id == id)) { &mut self.items[i] } else { - &mut self.items[self.cursor] + self.active_mut() } } } diff --git a/yazi-core/src/tab/commands/arrow.rs b/yazi-core/src/tab/commands/arrow.rs index 6e29cd55..c635d449 100644 --- a/yazi-core/src/tab/commands/arrow.rs +++ b/yazi-core/src/tab/commands/arrow.rs @@ -42,7 +42,7 @@ impl Tab { } } - ManagerProxy::hover(None, self.idx); + ManagerProxy::hover(None, self.id); render!(); } } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index ae693168..69799cc2 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -66,7 +66,7 @@ impl Tab { self.backstack.push(opt.target.clone()); } - Pubsub::pub_from_cd(self.idx, self.cwd()); + Pubsub::pub_from_cd(self.id, self.cwd()); ManagerProxy::refresh(); render!(); } diff --git a/yazi-core/src/tab/commands/filter_do.rs b/yazi-core/src/tab/commands/filter_do.rs index d7e1ded5..44606628 100644 --- a/yazi-core/src/tab/commands/filter_do.rs +++ b/yazi-core/src/tab/commands/filter_do.rs @@ -27,7 +27,7 @@ impl Tab { self.current.repos(hovered.as_ref().map(|u| u.as_urn())); if self.hovered().map(|f| f.urn()) != hovered.as_ref().map(|u| u.as_urn()) { - ManagerProxy::hover(None, self.idx); + ManagerProxy::hover(None, self.id); } render!(); diff --git a/yazi-core/src/tab/commands/hidden.rs b/yazi-core/src/tab/commands/hidden.rs index 527f6886..266b119d 100644 --- a/yazi-core/src/tab/commands/hidden.rs +++ b/yazi-core/src/tab/commands/hidden.rs @@ -15,7 +15,7 @@ impl Tab { self.apply_files_attrs(); if hovered.as_ref() != self.hovered().map(|f| &f.url) { - ManagerProxy::hover(hovered, self.idx); + ManagerProxy::hover(hovered, self.id); } else if self.hovered().is_some_and(|f| f.is_dir()) { ManagerProxy::peek(true); } diff --git a/yazi-core/src/tab/commands/reveal.rs b/yazi-core/src/tab/commands/reveal.rs index 18b7e2d7..00edc64f 100644 --- a/yazi-core/src/tab/commands/reveal.rs +++ b/yazi-core/src/tab/commands/reveal.rs @@ -30,6 +30,6 @@ impl Tab { self.cd(parent.clone()); 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.id); } } diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index 345425de..516925a8 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -7,14 +7,13 @@ use yazi_adapter::Dimension; use yazi_config::{LAYOUT, popup::{Origin, Position}}; use yazi_fs::{Folder, FolderStage}; use yazi_macro::render; -use yazi_shared::fs::{File, Url}; +use yazi_shared::{Id, Ids, fs::{File, Url}}; use super::{Backstack, Config, Finder, History, Mode, Preview}; use crate::tab::Selected; -#[derive(Default)] pub struct Tab { - pub idx: usize, + pub id: Id, pub mode: Mode, pub conf: Config, pub current: Folder, @@ -29,6 +28,28 @@ pub struct Tab { pub search: Option>>, } +impl Default for Tab { + fn default() -> Self { + static IDS: Ids = Ids::new(); + + Self { + id: IDS.next(), + mode: Default::default(), + conf: Default::default(), + current: Default::default(), + parent: Default::default(), + + backstack: Default::default(), + history: Default::default(), + selected: Default::default(), + + preview: Default::default(), + finder: Default::default(), + search: Default::default(), + } + } +} + impl Tab { pub fn shutdown(&mut self) { if let Some(handle) = self.search.take() { diff --git a/yazi-dds/src/body/cd.rs b/yazi-dds/src/body/cd.rs index 587a6f1b..c6711c75 100644 --- a/yazi-dds/src/body/cd.rs +++ b/yazi-dds/src/body/cd.rs @@ -2,13 +2,13 @@ use std::borrow::Cow; use mlua::{IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; -use yazi_shared::fs::Url; +use yazi_shared::{Id, fs::Url}; use super::Body; #[derive(Debug, Serialize, Deserialize)] pub struct BodyCd<'a> { - pub tab: usize, + pub tab: Id, pub url: Cow<'a, Url>, #[serde(skip)] dummy: bool, @@ -16,14 +16,14 @@ pub struct BodyCd<'a> { impl<'a> BodyCd<'a> { #[inline] - pub fn borrowed(tab: usize, url: &'a Url) -> Body<'a> { + pub fn borrowed(tab: Id, url: &'a Url) -> Body<'a> { Self { tab, url: Cow::Borrowed(url), dummy: false }.into() } } impl BodyCd<'static> { #[inline] - pub fn dummy(tab: usize) -> Body<'static> { + pub fn dummy(tab: Id) -> Body<'static> { Self { tab, url: Default::default(), dummy: true }.into() } } @@ -36,11 +36,11 @@ impl IntoLua<'_> for BodyCd<'static> { fn into_lua(self, lua: &Lua) -> mlua::Result { if let Some(Cow::Owned(url)) = Some(self.url).filter(|_| !self.dummy) { lua.create_table_from([ - ("tab", self.tab.into_lua(lua)?), + ("tab", self.tab.get().into_lua(lua)?), ("url", lua.create_any_userdata(url)?.into_lua(lua)?), ])? } else { - lua.create_table_from([("tab", self.tab)])? + lua.create_table_from([("tab", self.tab.get())])? } .into_lua(lua) } diff --git a/yazi-dds/src/body/hover.rs b/yazi-dds/src/body/hover.rs index e3916fa4..893ca699 100644 --- a/yazi-dds/src/body/hover.rs +++ b/yazi-dds/src/body/hover.rs @@ -2,26 +2,26 @@ use std::borrow::Cow; use mlua::{IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; -use yazi_shared::fs::Url; +use yazi_shared::{Id, fs::Url}; use super::Body; #[derive(Debug, Serialize, Deserialize)] pub struct BodyHover<'a> { - pub tab: usize, + pub tab: Id, pub url: Option>, } impl<'a> BodyHover<'a> { #[inline] - pub fn borrowed(tab: usize, url: Option<&'a Url>) -> Body<'a> { + pub fn borrowed(tab: Id, url: Option<&'a Url>) -> Body<'a> { Self { tab, url: url.map(Cow::Borrowed) }.into() } } impl BodyHover<'static> { #[inline] - pub fn dummy(tab: usize) -> Body<'static> { Self { tab, url: None }.into() } + pub fn dummy(tab: Id) -> Body<'static> { Self { tab, url: None }.into() } } impl<'a> From> for Body<'a> { @@ -32,11 +32,11 @@ impl IntoLua<'_> for BodyHover<'static> { fn into_lua(self, lua: &Lua) -> mlua::Result { if let Some(Cow::Owned(url)) = self.url { lua.create_table_from([ - ("tab", self.tab.into_lua(lua)?), + ("tab", self.tab.get().into_lua(lua)?), ("url", lua.create_any_userdata(url)?.into_lua(lua)?), ])? } else { - lua.create_table_from([("tab", self.tab)])? + lua.create_table_from([("tab", self.tab.get())])? } .into_lua(lua) } diff --git a/yazi-dds/src/pubsub.rs b/yazi-dds/src/pubsub.rs index 59035c6e..0be6b36d 100644 --- a/yazi-dds/src/pubsub.rs +++ b/yazi-dds/src/pubsub.rs @@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet}; use mlua::Function; use parking_lot::RwLock; use yazi_boot::BOOT; -use yazi_shared::{RoCell, fs::Url}; +use yazi_shared::{Id, RoCell, fs::Url}; use crate::{Client, ID, PEERS, body::{Body, BodyBulk, BodyCd, BodyDelete, BodyHi, BodyHover, BodyMove, BodyMoveItem, BodyRename, BodyTab, BodyTrash, BodyYank}}; @@ -88,7 +88,7 @@ impl Pubsub { true } - pub fn pub_from_cd(tab: usize, url: &Url) { + pub fn pub_from_cd(tab: Id, url: &Url) { if LOCAL.read().contains_key("cd") { Self::pub_(BodyCd::dummy(tab)); } @@ -100,7 +100,7 @@ impl Pubsub { } } - pub fn pub_from_hover(tab: usize, url: Option<&Url>) { + pub fn pub_from_hover(tab: Id, url: Option<&Url>) { if LOCAL.read().contains_key("hover") { Self::pub_(BodyHover::dummy(tab)); } diff --git a/yazi-fm/src/lives/tab.rs b/yazi-fm/src/lives/tab.rs index e9568311..eaff877b 100644 --- a/yazi-fm/src/lives/tab.rs +++ b/yazi-fm/src/lives/tab.rs @@ -23,7 +23,7 @@ impl Tab { pub(super) fn register(lua: &Lua) -> mlua::Result<()> { lua.register_userdata_type::(|reg| { - reg.add_field_method_get("idx", |_, me| Ok(me.idx + 1)); + reg.add_field_method_get("id", |_, me| Ok(me.id.get())); reg.add_method("name", |lua, me, ()| { lua.create_string(me.current.url.name().as_encoded_bytes()) }); diff --git a/yazi-fs/src/files.rs b/yazi-fs/src/files.rs index fc38f0b6..482e5750 100644 --- a/yazi-fs/src/files.rs +++ b/yazi-fs/src/files.rs @@ -1,15 +1,15 @@ -use std::{collections::{HashMap, HashSet}, mem, ops::Deref, sync::atomic::Ordering}; +use std::{collections::{HashMap, HashSet}, mem, ops::Deref}; use tokio::{fs::{self, DirEntry}, select, sync::mpsc::{self, UnboundedReceiver}}; use yazi_config::{MANAGER, manager::SortBy}; -use yazi_shared::fs::{Cha, FILES_TICKET, File, FilesOp, Url, Urn, UrnBuf, maybe_exists}; +use yazi_shared::{Id, fs::{Cha, FILES_TICKET, File, FilesOp, Url, Urn, UrnBuf, maybe_exists}}; use super::{FilesSorter, Filter}; pub struct Files { hidden: Vec, items: Vec, - ticket: u64, + ticket: Id, version: u64, pub revision: u64, @@ -118,7 +118,7 @@ impl Files { impl Files { pub fn update_full(&mut self, files: Vec) { - self.ticket = FILES_TICKET.fetch_add(1, Ordering::Relaxed); + self.ticket = FILES_TICKET.next(); (self.hidden, self.items) = self.split_files(files); if !self.items.is_empty() { @@ -126,7 +126,7 @@ impl Files { } } - pub fn update_part(&mut self, files: Vec, ticket: u64) { + pub fn update_part(&mut self, files: Vec, ticket: Id) { if !files.is_empty() { if ticket != self.ticket { return; @@ -162,7 +162,7 @@ impl Files { } pub fn update_ioerr(&mut self) { - self.ticket = FILES_TICKET.fetch_add(1, Ordering::Relaxed); + self.ticket = FILES_TICKET.next(); self.hidden.clear(); self.items.clear(); } @@ -349,7 +349,7 @@ impl Files { // --- Ticket #[inline] - pub fn ticket(&self) -> u64 { self.ticket } + pub fn ticket(&self) -> Id { self.ticket } // --- Sorter #[inline] diff --git a/yazi-plugin/src/external/highlighter.rs b/yazi-plugin/src/external/highlighter.rs index dfc506ec..ef21db55 100644 --- a/yazi-plugin/src/external/highlighter.rs +++ b/yazi-plugin/src/external/highlighter.rs @@ -1,13 +1,13 @@ -use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}, sync::atomic::{AtomicUsize, Ordering}}; +use std::{borrow::Cow, io::Cursor, mem, path::{Path, PathBuf}}; use anyhow::{Result, anyhow}; use ratatui::{layout::Rect, text::{Line, Span, Text}}; use syntect::{LoadingError, dumps, easy::HighlightLines, highlighting::{self, Theme, ThemeSet}, parsing::{SyntaxReference, SyntaxSet}}; use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}, sync::OnceCell}; use yazi_config::{PREVIEW, THEME, preview::PreviewWrap}; -use yazi_shared::{errors::PeekError, replace_to_printable}; +use yazi_shared::{Ids, errors::PeekError, replace_to_printable}; -static INCR: AtomicUsize = AtomicUsize::new(0); +static INCR: Ids = Ids::new(); static SYNTECT: OnceCell<(Theme, SyntaxSet)> = OnceCell::const_new(); pub struct Highlighter { @@ -39,7 +39,7 @@ impl Highlighter { } #[inline] - pub fn abort() { INCR.fetch_add(1, Ordering::Relaxed); } + pub fn abort() { INCR.next(); } pub async fn highlight(&self, skip: usize, area: Rect) -> Result, PeekError> { let mut reader = BufReader::new(File::open(&self.path).await?); @@ -104,13 +104,13 @@ impl Highlighter { after: Vec, syntax: &'static SyntaxReference, ) -> Result, PeekError> { - let ticket = INCR.load(Ordering::Relaxed); + let ticket = INCR.current(); let (theme, syntaxes) = Self::init().await; tokio::task::spawn_blocking(move || { let mut h = HighlightLines::new(syntax, theme); for line in before { - if ticket != INCR.load(Ordering::Relaxed) { + if ticket != INCR.current() { return Err("Highlighting cancelled".into()); } h.highlight_line(&line, syntaxes).map_err(|e| anyhow!(e))?; @@ -119,7 +119,7 @@ impl Highlighter { let indent = PREVIEW.indent(); let mut lines = Vec::with_capacity(after.len()); for line in after { - if ticket != INCR.load(Ordering::Relaxed) { + if ticket != INCR.current() { return Err("Highlighting cancelled".into()); } diff --git a/yazi-proxy/src/manager.rs b/yazi-proxy/src/manager.rs index e3a1b171..1a4337f2 100644 --- a/yazi-proxy/src/manager.rs +++ b/yazi-proxy/src/manager.rs @@ -1,5 +1,5 @@ use yazi_macro::emit; -use yazi_shared::{Layer, event::Cmd, fs::Url}; +use yazi_shared::{Id, Layer, event::Cmd, fs::Url}; use crate::options::OpenDoOpt; @@ -12,7 +12,7 @@ impl ManagerProxy { } #[inline] - pub fn hover(url: Option, tab: usize) { + pub fn hover(url: Option, tab: Id) { emit!(Call( Cmd::args("hover", &url.map_or_else(Vec::new, |u| vec![u])).with("tab", tab), Layer::Manager diff --git a/yazi-shared/src/event/data.rs b/yazi-shared/src/event/data.rs index 558d34ff..e5675a98 100644 --- a/yazi-shared/src/event/data.rs +++ b/yazi-shared/src/event/data.rs @@ -143,3 +143,5 @@ impl_integer_as!(isize, as_isize); impl_integer_as!(i16, as_i16); impl_number_as!(f64, as_f64); + +impl_integer_as!(crate::Id, as_id); diff --git a/yazi-shared/src/fs/op.rs b/yazi-shared/src/fs/op.rs index d7c7721f..2f0a7605 100644 --- a/yazi-shared/src/fs/op.rs +++ b/yazi-shared/src/fs/op.rs @@ -1,15 +1,15 @@ -use std::{collections::{HashMap, HashSet}, sync::atomic::{AtomicU64, Ordering}}; +use std::collections::{HashMap, HashSet}; use super::{Cha, File, UrnBuf}; -use crate::{Layer, event::Cmd, fs::Url}; +use crate::{Id, Ids, Layer, event::Cmd, fs::Url}; -pub static FILES_TICKET: AtomicU64 = AtomicU64::new(0); +pub static FILES_TICKET: Ids = Ids::new(); #[derive(Clone, Debug)] pub enum FilesOp { Full(Url, Vec, Cha), - Part(Url, Vec, u64), - Done(Url, Cha, u64), + Part(Url, Vec, Id), + Done(Url, Cha, Id), Size(Url, HashMap), IOErr(Url, std::io::ErrorKind), @@ -41,8 +41,8 @@ impl FilesOp { crate::event::Event::Call(Cmd::new("update_files").with_any("op", self), Layer::Manager).emit(); } - pub fn prepare(cwd: &Url) -> u64 { - let ticket = FILES_TICKET.fetch_add(1, Ordering::Relaxed); + pub fn prepare(cwd: &Url) -> Id { + let ticket = FILES_TICKET.next(); Self::Part(cwd.clone(), vec![], ticket).emit(); ticket } diff --git a/yazi-shared/src/id.rs b/yazi-shared/src/id.rs new file mode 100644 index 00000000..ab5f1523 --- /dev/null +++ b/yazi-shared/src/id.rs @@ -0,0 +1,54 @@ +use std::{fmt::Display, str::FromStr, sync::atomic::{AtomicUsize, Ordering}}; + +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq, Serialize, Deserialize)] +pub struct Id(usize); + +impl Id { + #[inline] + pub fn get(&self) -> usize { self.0 } +} + +impl Display for Id { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.0.fmt(f) } +} + +impl FromStr for Id { + type Err = ::Err; + + fn from_str(s: &str) -> Result { s.parse().map(Self) } +} + +impl TryFrom for Id { + type Error = >::Error; + + fn try_from(value: i64) -> Result { usize::try_from(value).map(Self) } +} + +// --- Ids +pub struct Ids { + next: AtomicUsize, +} + +impl Ids { + #[inline] + pub const fn new() -> Self { Self { next: AtomicUsize::new(1) } } + + #[inline] + pub fn next(&self) -> Id { + loop { + let old = self.next.fetch_add(1, Ordering::Relaxed); + if old != 0 { + return Id(old); + } + } + } + + #[inline] + pub fn current(&self) -> Id { Id(self.next.load(Ordering::Relaxed)) } +} + +impl Default for Ids { + fn default() -> Self { Self::new() } +} diff --git a/yazi-shared/src/lib.rs b/yazi-shared/src/lib.rs index fd5b37be..0b3ff28e 100644 --- a/yazi-shared/src/lib.rs +++ b/yazi-shared/src/lib.rs @@ -2,10 +2,7 @@ yazi_macro::mod_pub!(errors event fs shell theme translit); -yazi_macro::mod_flat!( - chars condition debounce env layer natsort number os rand ro_cell terminal throttle - time xdg -); +yazi_macro::mod_flat!(chars condition debounce env id layer natsort number os rand ro_cell terminal throttle time xdg); pub fn init() { #[cfg(unix)]