Skip to content

Commit e8c1d62

Browse files
authored
fix: use a unique Id for each tab (#1826)
1 parent 35d781e commit e8c1d62

File tree

24 files changed

+143
-82
lines changed

24 files changed

+143
-82
lines changed

Diff for: yazi-core/src/manager/commands/hover.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,18 @@ use std::{collections::HashSet, path::PathBuf};
22

33
use yazi_dds::Pubsub;
44
use yazi_macro::render;
5-
use yazi_shared::{event::{Cmd, Data}, fs::{Url, Urn}};
5+
use yazi_shared::{Id, event::{Cmd, Data}, fs::{Url, Urn}};
66

77
use crate::manager::Manager;
88

99
struct Opt {
1010
url: Option<Url>,
11-
tab: Option<usize>,
11+
tab: Option<Id>,
1212
}
1313

1414
impl From<Cmd> for Opt {
1515
fn from(mut c: Cmd) -> Self {
16-
Self {
17-
url: c.take_first().and_then(Data::into_url),
18-
tab: c.get("tab").and_then(Data::as_usize),
19-
}
16+
Self { url: c.take_first().and_then(Data::into_url), tab: c.get("tab").and_then(Data::as_id) }
2017
}
2118
}
2219
impl From<Option<Url>> for Opt {
@@ -49,10 +46,10 @@ impl Manager {
4946
self.watcher.watch(to_watch);
5047

5148
// Publish through DDS
52-
Pubsub::pub_from_hover(self.active().idx, self.hovered().map(|h| &h.url));
49+
Pubsub::pub_from_hover(self.active().id, self.hovered().map(|h| &h.url));
5350
}
5451

55-
fn hover_do(&mut self, url: Url, tab: Option<usize>) {
52+
fn hover_do(&mut self, url: Url, tab: Option<Id>) {
5653
// Hover on the file
5754
if let Ok(p) = url.strip_prefix(&self.current_or(tab).url).map(PathBuf::from) {
5855
render!(self.current_or_mut(tab).repos(Some(Urn::new(&p))));

Diff for: yazi-core/src/manager/commands/tab_close.rs

-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ impl Tabs {
3030
self.set_idx(self.absolute(1));
3131
}
3232

33-
self.reorder();
3433
render!();
3534
}
3635
}

Diff for: yazi-core/src/manager/commands/tab_create.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ impl Tabs {
3636
return;
3737
}
3838

39-
let mut tab = Tab { idx: self.cursor + 1, ..Default::default() };
40-
39+
let mut tab = Tab::default();
4140
if !opt.current {
4241
tab.cd(opt.url);
4342
} else if let Some(h) = self.active().hovered() {
@@ -52,7 +51,6 @@ impl Tabs {
5251

5352
self.items.insert(self.cursor + 1, tab);
5453
self.set_idx(self.cursor + 1);
55-
self.reorder();
5654
render!();
5755
}
5856
}

Diff for: yazi-core/src/manager/commands/tab_swap.rs

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ impl Tabs {
2121

2222
self.items.swap(self.cursor, idx);
2323
self.set_idx(idx);
24-
self.reorder();
2524
render!();
2625
}
2726
}

Diff for: yazi-core/src/manager/commands/update_files.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl Manager {
8787
return;
8888
}
8989

90-
ManagerProxy::hover(None, tab.idx); // Re-hover in next loop
90+
ManagerProxy::hover(None, tab.id); // Re-hover in next loop
9191
ManagerProxy::update_paged(); // Update for paged files in next loop
9292
if calc {
9393
tasks.prework_sorted(&tab.current.files);

Diff for: yazi-core/src/manager/manager.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use ratatui::layout::Rect;
22
use yazi_adapter::Dimension;
33
use yazi_config::popup::{Origin, Position};
44
use yazi_fs::Folder;
5-
use yazi_shared::fs::{File, Url};
5+
use yazi_shared::{Id, fs::{File, Url}};
66

77
use super::{Mimetype, Tabs, Watcher, Yanked};
88
use crate::tab::Tab;
@@ -48,10 +48,10 @@ impl Manager {
4848
pub fn active_mut(&mut self) -> &mut Tab { self.tabs.active_mut() }
4949

5050
#[inline]
51-
pub fn active_or(&self, idx: Option<usize>) -> &Tab { self.tabs.active_or(idx) }
51+
pub fn active_or(&self, id: Option<Id>) -> &Tab { self.tabs.active_or(id) }
5252

5353
#[inline]
54-
pub fn active_or_mut(&mut self, idx: Option<usize>) -> &mut Tab { self.tabs.active_or_mut(idx) }
54+
pub fn active_or_mut(&mut self, id: Option<Id>) -> &mut Tab { self.tabs.active_or_mut(id) }
5555

5656
#[inline]
5757
pub fn current(&self) -> &Folder { &self.active().current }
@@ -60,10 +60,10 @@ impl Manager {
6060
pub fn current_mut(&mut self) -> &mut Folder { &mut self.active_mut().current }
6161

6262
#[inline]
63-
pub fn current_or(&self, idx: Option<usize>) -> &Folder { &self.active_or(idx).current }
63+
pub fn current_or(&self, idx: Option<Id>) -> &Folder { &self.active_or(idx).current }
6464

6565
#[inline]
66-
pub fn current_or_mut(&mut self, idx: Option<usize>) -> &mut Folder {
66+
pub fn current_or_mut(&mut self, idx: Option<Id>) -> &mut Folder {
6767
&mut self.active_or_mut(idx).current
6868
}
6969

Diff for: yazi-core/src/manager/tabs.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut};
33
use yazi_boot::BOOT;
44
use yazi_dds::Pubsub;
55
use yazi_proxy::ManagerProxy;
6-
use yazi_shared::fs::Url;
6+
use yazi_shared::{Id, fs::Url};
77

88
use crate::tab::Tab;
99

@@ -16,7 +16,6 @@ impl Tabs {
1616
pub fn make() -> Self {
1717
let mut tabs =
1818
Self { cursor: 0, items: (0..BOOT.cwds.len()).map(|_| Tab::default()).collect() };
19-
tabs.reorder();
2019

2120
for (i, tab) in tabs.iter_mut().enumerate() {
2221
let file = &BOOT.files[i];
@@ -37,11 +36,6 @@ impl Tabs {
3736
}
3837
}
3938

40-
#[inline]
41-
pub(super) fn reorder(&mut self) {
42-
self.items.iter_mut().enumerate().for_each(|(i, tab)| tab.idx = i);
43-
}
44-
4539
pub(super) fn set_idx(&mut self, idx: usize) {
4640
// Reset the preview of the last active tab
4741
if let Some(active) = self.items.get_mut(self.cursor) {
@@ -63,16 +57,16 @@ impl Tabs {
6357
pub(super) fn active_mut(&mut self) -> &mut Tab { &mut self.items[self.cursor] }
6458

6559
#[inline]
66-
pub fn active_or(&self, idx: Option<usize>) -> &Tab {
67-
idx.and_then(|i| self.items.get(i)).unwrap_or(&self.items[self.cursor])
60+
pub fn active_or(&self, id: Option<Id>) -> &Tab {
61+
id.and_then(|id| self.iter().find(|&t| t.id == id)).unwrap_or(self.active())
6862
}
6963

7064
#[inline]
71-
pub(super) fn active_or_mut(&mut self, idx: Option<usize>) -> &mut Tab {
72-
if let Some(i) = idx.filter(|&i| i < self.items.len()) {
65+
pub(super) fn active_or_mut(&mut self, id: Option<Id>) -> &mut Tab {
66+
if let Some(i) = id.and_then(|id| self.iter().position(|t| t.id == id)) {
7367
&mut self.items[i]
7468
} else {
75-
&mut self.items[self.cursor]
69+
self.active_mut()
7670
}
7771
}
7872
}

Diff for: yazi-core/src/tab/commands/arrow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl Tab {
4242
}
4343
}
4444

45-
ManagerProxy::hover(None, self.idx);
45+
ManagerProxy::hover(None, self.id);
4646
render!();
4747
}
4848
}

Diff for: yazi-core/src/tab/commands/cd.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ impl Tab {
6666
self.backstack.push(opt.target.clone());
6767
}
6868

69-
Pubsub::pub_from_cd(self.idx, self.cwd());
69+
Pubsub::pub_from_cd(self.id, self.cwd());
7070
ManagerProxy::refresh();
7171
render!();
7272
}

Diff for: yazi-core/src/tab/commands/filter_do.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ impl Tab {
2727

2828
self.current.repos(hovered.as_ref().map(|u| u.as_urn()));
2929
if self.hovered().map(|f| f.urn()) != hovered.as_ref().map(|u| u.as_urn()) {
30-
ManagerProxy::hover(None, self.idx);
30+
ManagerProxy::hover(None, self.id);
3131
}
3232

3333
render!();

Diff for: yazi-core/src/tab/commands/hidden.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl Tab {
1515
self.apply_files_attrs();
1616

1717
if hovered.as_ref() != self.hovered().map(|f| &f.url) {
18-
ManagerProxy::hover(hovered, self.idx);
18+
ManagerProxy::hover(hovered, self.id);
1919
} else if self.hovered().is_some_and(|f| f.is_dir()) {
2020
ManagerProxy::peek(true);
2121
}

Diff for: yazi-core/src/tab/commands/reveal.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ impl Tab {
3030

3131
self.cd(parent.clone());
3232
FilesOp::Creating(parent, vec![File::from_dummy(opt.target.clone(), None)]).emit();
33-
ManagerProxy::hover(Some(opt.target), self.idx);
33+
ManagerProxy::hover(Some(opt.target), self.id);
3434
}
3535
}

Diff for: yazi-core/src/tab/tab.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ use yazi_adapter::Dimension;
77
use yazi_config::{LAYOUT, popup::{Origin, Position}};
88
use yazi_fs::{Folder, FolderStage};
99
use yazi_macro::render;
10-
use yazi_shared::fs::{File, Url};
10+
use yazi_shared::{Id, Ids, fs::{File, Url}};
1111

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

15-
#[derive(Default)]
1615
pub struct Tab {
17-
pub idx: usize,
16+
pub id: Id,
1817
pub mode: Mode,
1918
pub conf: Config,
2019
pub current: Folder,
@@ -29,6 +28,28 @@ pub struct Tab {
2928
pub search: Option<JoinHandle<Result<()>>>,
3029
}
3130

31+
impl Default for Tab {
32+
fn default() -> Self {
33+
static IDS: Ids = Ids::new();
34+
35+
Self {
36+
id: IDS.next(),
37+
mode: Default::default(),
38+
conf: Default::default(),
39+
current: Default::default(),
40+
parent: Default::default(),
41+
42+
backstack: Default::default(),
43+
history: Default::default(),
44+
selected: Default::default(),
45+
46+
preview: Default::default(),
47+
finder: Default::default(),
48+
search: Default::default(),
49+
}
50+
}
51+
}
52+
3253
impl Tab {
3354
pub fn shutdown(&mut self) {
3455
if let Some(handle) = self.search.take() {

Diff for: yazi-dds/src/body/cd.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@ use std::borrow::Cow;
22

33
use mlua::{IntoLua, Lua, Value};
44
use serde::{Deserialize, Serialize};
5-
use yazi_shared::fs::Url;
5+
use yazi_shared::{Id, fs::Url};
66

77
use super::Body;
88

99
#[derive(Debug, Serialize, Deserialize)]
1010
pub struct BodyCd<'a> {
11-
pub tab: usize,
11+
pub tab: Id,
1212
pub url: Cow<'a, Url>,
1313
#[serde(skip)]
1414
dummy: bool,
1515
}
1616

1717
impl<'a> BodyCd<'a> {
1818
#[inline]
19-
pub fn borrowed(tab: usize, url: &'a Url) -> Body<'a> {
19+
pub fn borrowed(tab: Id, url: &'a Url) -> Body<'a> {
2020
Self { tab, url: Cow::Borrowed(url), dummy: false }.into()
2121
}
2222
}
2323

2424
impl BodyCd<'static> {
2525
#[inline]
26-
pub fn dummy(tab: usize) -> Body<'static> {
26+
pub fn dummy(tab: Id) -> Body<'static> {
2727
Self { tab, url: Default::default(), dummy: true }.into()
2828
}
2929
}
@@ -36,11 +36,11 @@ impl IntoLua<'_> for BodyCd<'static> {
3636
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
3737
if let Some(Cow::Owned(url)) = Some(self.url).filter(|_| !self.dummy) {
3838
lua.create_table_from([
39-
("tab", self.tab.into_lua(lua)?),
39+
("tab", self.tab.get().into_lua(lua)?),
4040
("url", lua.create_any_userdata(url)?.into_lua(lua)?),
4141
])?
4242
} else {
43-
lua.create_table_from([("tab", self.tab)])?
43+
lua.create_table_from([("tab", self.tab.get())])?
4444
}
4545
.into_lua(lua)
4646
}

Diff for: yazi-dds/src/body/hover.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@ use std::borrow::Cow;
22

33
use mlua::{IntoLua, Lua, Value};
44
use serde::{Deserialize, Serialize};
5-
use yazi_shared::fs::Url;
5+
use yazi_shared::{Id, fs::Url};
66

77
use super::Body;
88

99
#[derive(Debug, Serialize, Deserialize)]
1010
pub struct BodyHover<'a> {
11-
pub tab: usize,
11+
pub tab: Id,
1212
pub url: Option<Cow<'a, Url>>,
1313
}
1414

1515
impl<'a> BodyHover<'a> {
1616
#[inline]
17-
pub fn borrowed(tab: usize, url: Option<&'a Url>) -> Body<'a> {
17+
pub fn borrowed(tab: Id, url: Option<&'a Url>) -> Body<'a> {
1818
Self { tab, url: url.map(Cow::Borrowed) }.into()
1919
}
2020
}
2121

2222
impl BodyHover<'static> {
2323
#[inline]
24-
pub fn dummy(tab: usize) -> Body<'static> { Self { tab, url: None }.into() }
24+
pub fn dummy(tab: Id) -> Body<'static> { Self { tab, url: None }.into() }
2525
}
2626

2727
impl<'a> From<BodyHover<'a>> for Body<'a> {
@@ -32,11 +32,11 @@ impl IntoLua<'_> for BodyHover<'static> {
3232
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
3333
if let Some(Cow::Owned(url)) = self.url {
3434
lua.create_table_from([
35-
("tab", self.tab.into_lua(lua)?),
35+
("tab", self.tab.get().into_lua(lua)?),
3636
("url", lua.create_any_userdata(url)?.into_lua(lua)?),
3737
])?
3838
} else {
39-
lua.create_table_from([("tab", self.tab)])?
39+
lua.create_table_from([("tab", self.tab.get())])?
4040
}
4141
.into_lua(lua)
4242
}

Diff for: yazi-dds/src/pubsub.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::collections::{HashMap, HashSet};
33
use mlua::Function;
44
use parking_lot::RwLock;
55
use yazi_boot::BOOT;
6-
use yazi_shared::{RoCell, fs::Url};
6+
use yazi_shared::{Id, RoCell, fs::Url};
77

88
use crate::{Client, ID, PEERS, body::{Body, BodyBulk, BodyCd, BodyDelete, BodyHi, BodyHover, BodyMove, BodyMoveItem, BodyRename, BodyTab, BodyTrash, BodyYank}};
99

@@ -88,7 +88,7 @@ impl Pubsub {
8888
true
8989
}
9090

91-
pub fn pub_from_cd(tab: usize, url: &Url) {
91+
pub fn pub_from_cd(tab: Id, url: &Url) {
9292
if LOCAL.read().contains_key("cd") {
9393
Self::pub_(BodyCd::dummy(tab));
9494
}
@@ -100,7 +100,7 @@ impl Pubsub {
100100
}
101101
}
102102

103-
pub fn pub_from_hover(tab: usize, url: Option<&Url>) {
103+
pub fn pub_from_hover(tab: Id, url: Option<&Url>) {
104104
if LOCAL.read().contains_key("hover") {
105105
Self::pub_(BodyHover::dummy(tab));
106106
}

Diff for: yazi-fm/src/lives/tab.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ impl Tab {
2323

2424
pub(super) fn register(lua: &Lua) -> mlua::Result<()> {
2525
lua.register_userdata_type::<Self>(|reg| {
26-
reg.add_field_method_get("idx", |_, me| Ok(me.idx + 1));
26+
reg.add_field_method_get("id", |_, me| Ok(me.id.get()));
2727
reg.add_method("name", |lua, me, ()| {
2828
lua.create_string(me.current.url.name().as_encoded_bytes())
2929
});

0 commit comments

Comments
 (0)