diff --git a/yazi-core/src/folder/folder.rs b/yazi-core/src/folder/folder.rs index e04daa978..b366bdb9a 100644 --- a/yazi-core/src/folder/folder.rs +++ b/yazi-core/src/folder/folder.rs @@ -22,12 +22,8 @@ pub struct Folder { pub tracing: bool, } -impl From for Folder { - fn from(cwd: Url) -> Self { Self { cwd, ..Default::default() } } -} - impl From<&Url> for Folder { - fn from(cwd: &Url) -> Self { Self::from(cwd.clone()) } + fn from(cwd: &Url) -> Self { Self { cwd: cwd.clone(), ..Default::default() } } } impl Folder { diff --git a/yazi-core/src/manager/commands/tab_create.rs b/yazi-core/src/manager/commands/tab_create.rs index 5e067a2d5..4f0793057 100644 --- a/yazi-core/src/manager/commands/tab_create.rs +++ b/yazi-core/src/manager/commands/tab_create.rs @@ -29,9 +29,10 @@ impl Tabs { let opt = opt.into() as Opt; let url = if opt.current { self.active().current.cwd.to_owned() } else { opt.url.unwrap() }; - let mut tab = Tab::from(url); + let mut tab = Tab::default(); tab.conf = self.active().conf.clone(); tab.apply_files_attrs(); + tab.cd(url); self.items.insert(self.cursor + 1, tab); self.set_idx(self.cursor + 1); diff --git a/yazi-core/src/manager/tabs.rs b/yazi-core/src/manager/tabs.rs index ef2ccd3bd..100f6afea 100644 --- a/yazi-core/src/manager/tabs.rs +++ b/yazi-core/src/manager/tabs.rs @@ -13,12 +13,13 @@ pub struct Tabs { impl Tabs { pub fn make() -> Self { - let mut tabs = Self { cursor: 0, items: vec![Tab::from(Url::from(&BOOT.cwd))] }; + let mut tabs = Self { cursor: 0, items: vec![Tab::default()] }; if let Some(file) = &BOOT.file { tabs.items[0].reveal(Url::from(BOOT.cwd.join(file))); + } else { + tabs.items[0].cd(Url::from(&BOOT.cwd)); } - ManagerProxy::refresh(); tabs } diff --git a/yazi-core/src/tab/backstack.rs b/yazi-core/src/tab/backstack.rs index c65375b9b..a485dbe55 100644 --- a/yazi-core/src/tab/backstack.rs +++ b/yazi-core/src/tab/backstack.rs @@ -1,12 +1,16 @@ +#[derive(Default)] pub struct Backstack { cursor: usize, stack: Vec, } impl Backstack { - pub fn new(item: T) -> Self { Self { cursor: 0, stack: vec![item] } } - pub fn push(&mut self, item: T) { + if self.stack.is_empty() { + self.stack.push(item); + return; + } + if self.stack[self.cursor] == item { return; } @@ -27,10 +31,6 @@ impl Backstack { } } - #[cfg(test)] - #[inline] - pub fn current(&self) -> &T { &self.stack[self.cursor] } - pub fn shift_backward(&mut self) -> Option<&T> { if self.cursor > 0 { self.cursor -= 1; @@ -56,27 +56,28 @@ mod tests { #[test] fn test_backstack() { - let mut backstack = Backstack::::new(1); - assert_eq!(backstack.current(), &1); + let mut bs = Backstack::default(); + bs.push(1); + assert_eq!(bs.stack[bs.cursor], 1); - backstack.push(2); - backstack.push(3); - assert_eq!(backstack.current(), &3); + bs.push(2); + bs.push(3); + assert_eq!(bs.stack[bs.cursor], 3); - assert_eq!(backstack.shift_backward(), Some(&2)); - assert_eq!(backstack.shift_backward(), Some(&1)); - assert_eq!(backstack.shift_backward(), None); - assert_eq!(backstack.shift_backward(), None); - assert_eq!(backstack.current(), &1); - assert_eq!(backstack.shift_forward(), Some(&2)); - assert_eq!(backstack.shift_forward(), Some(&3)); - assert_eq!(backstack.shift_forward(), None); + assert_eq!(bs.shift_backward(), Some(&2)); + assert_eq!(bs.shift_backward(), Some(&1)); + assert_eq!(bs.shift_backward(), None); + assert_eq!(bs.shift_backward(), None); + assert_eq!(bs.stack[bs.cursor], 1); + assert_eq!(bs.shift_forward(), Some(&2)); + assert_eq!(bs.shift_forward(), Some(&3)); + assert_eq!(bs.shift_forward(), None); - backstack.shift_backward(); - backstack.push(4); + bs.shift_backward(); + bs.push(4); - assert_eq!(backstack.current(), &4); - assert_eq!(backstack.shift_forward(), None); - assert_eq!(backstack.shift_backward(), Some(&2)); + assert_eq!(bs.stack[bs.cursor], 4); + assert_eq!(bs.shift_forward(), None); + assert_eq!(bs.shift_backward(), Some(&2)); } } diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index 2fa257a3d..a5aa740c3 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -7,6 +7,7 @@ use yazi_shared::{fs::Url, render}; use super::{Backstack, Config, Finder, Mode, Preview}; use crate::{folder::{Folder, FolderStage}, tab::Selected}; +#[derive(Default)] pub struct Tab { pub idx: usize, pub mode: Mode, @@ -23,33 +24,6 @@ pub struct Tab { pub(super) search: Option>>, } -impl From for Tab { - fn from(url: Url) -> Self { - let parent = url.parent_url().map(Folder::from); - - Self { - idx: 0, - mode: Default::default(), - current: Folder::from(url.clone()), - parent, - - backstack: Backstack::new(url), - history: Default::default(), - selected: Default::default(), - - preview: Default::default(), - finder: None, - search: None, - - conf: Default::default(), - } - } -} - -impl From<&Url> for Tab { - fn from(url: &Url) -> Self { Self::from(url.clone()) } -} - impl Tab { pub fn shutdown(&mut self) { if let Some(handle) = self.search.take() { diff --git a/yazi-dds/src/body/body.rs b/yazi-dds/src/body/body.rs index cdfaff87f..25fd87ca7 100644 --- a/yazi-dds/src/body/body.rs +++ b/yazi-dds/src/body/body.rs @@ -2,7 +2,7 @@ use anyhow::Result; use mlua::{ExternalResult, IntoLua, Lua, Value}; use serde::{Deserialize, Serialize}; -use super::{BodyBulk, BodyCd, BodyCustom, BodyHey, BodyHi, BodyHover, BodyRename, BodyTabs, BodyYank}; +use super::{BodyBulk, BodyCd, BodyCustom, BodyHey, BodyHi, BodyHover, BodyRename, BodyYank}; use crate::Payload; #[derive(Debug, Serialize, Deserialize)] @@ -10,7 +10,6 @@ use crate::Payload; pub enum Body<'a> { Hi(BodyHi<'a>), Hey(BodyHey), - Tabs(BodyTabs<'a>), Cd(BodyCd<'a>), Hover(BodyHover<'a>), Rename(BodyRename<'a>), @@ -24,7 +23,6 @@ impl<'a> Body<'a> { Ok(match kind { "hi" => Body::Hi(serde_json::from_str(body)?), "hey" => Body::Hey(serde_json::from_str(body)?), - "tabs" => Body::Tabs(serde_json::from_str(body)?), "cd" => Body::Cd(serde_json::from_str(body)?), "hover" => Body::Hover(serde_json::from_str(body)?), "rename" => Body::Rename(serde_json::from_str(body)?), @@ -36,7 +34,7 @@ impl<'a> Body<'a> { pub fn from_lua(kind: &str, value: Value) -> Result { Ok(match kind { - "hi" | "hey" | "tabs" | "cd" | "hover" | "rename" | "bulk" | "yank" => { + "hi" | "hey" | "cd" | "hover" | "rename" | "bulk" | "yank" => { Err("Cannot construct system event from Lua").into_lua_err()? } _ => BodyCustom::from_lua(kind, value)?, @@ -48,7 +46,6 @@ impl<'a> Body<'a> { match self { Self::Hi(_) => "hi", Self::Hey(_) => "hey", - Self::Tabs(_) => "tabs", Self::Cd(_) => "cd", Self::Hover(_) => "hover", Self::Rename(_) => "rename", @@ -73,18 +70,13 @@ impl<'a> Body<'a> { } } - pub fn upgrade(self) -> Payload<'a> { - let severity = match self { - Body::Hi(_) => 0, - Body::Hey(_) => 0, - Body::Tabs(_) => 10, - Body::Cd(_) => 20, - Body::Hover(_) => 30, - Body::Rename(_) => 0, - Body::Bulk(_) => 0, - Body::Yank(_) => 40, - Body::Custom(_) => 0, - }; + #[inline] + pub fn with_receiver(self, receiver: u64) -> Payload<'a> { + Payload::new(self).with_receiver(receiver) + } + + #[inline] + pub fn with_severity(self, severity: u8) -> Payload<'a> { Payload::new(self).with_severity(severity) } } @@ -94,7 +86,6 @@ impl IntoLua<'_> for Body<'static> { match self { Body::Hi(b) => b.into_lua(lua), Body::Hey(b) => b.into_lua(lua), - Body::Tabs(b) => b.into_lua(lua), Body::Cd(b) => b.into_lua(lua), Body::Hover(b) => b.into_lua(lua), Body::Rename(b) => b.into_lua(lua), diff --git a/yazi-dds/src/body/mod.rs b/yazi-dds/src/body/mod.rs index 70fcf2e27..4570acd4c 100644 --- a/yazi-dds/src/body/mod.rs +++ b/yazi-dds/src/body/mod.rs @@ -8,7 +8,6 @@ mod hey; mod hi; mod hover; mod rename; -mod tabs; mod yank; pub use body::*; @@ -19,5 +18,4 @@ pub use hey::*; pub use hi::*; pub use hover::*; pub use rename::*; -pub use tabs::*; pub use yank::*; diff --git a/yazi-dds/src/body/tabs.rs b/yazi-dds/src/body/tabs.rs deleted file mode 100644 index f7b63b26d..000000000 --- a/yazi-dds/src/body/tabs.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::borrow::Cow; - -use mlua::{MetaMethod, UserData}; -use serde::{Deserialize, Serialize}; -use yazi_shared::fs::Url; - -use super::Body; - -#[derive(Debug, Serialize, Deserialize)] -pub struct BodyTabs<'a> { - pub cursor: usize, - pub items: Vec>, -} - -impl<'a> BodyTabs<'a> { - #[inline] - pub fn borrowed(cursor: usize, urls: &[&'a Url]) -> Body<'a> { - Self { cursor, items: urls.iter().map(|&u| BodyTabsItem::from(u)).collect() }.into() - } -} - -impl BodyTabs<'static> { - #[inline] - pub fn dummy(cursor: usize) -> Body<'static> { Self { cursor, items: Default::default() }.into() } -} - -impl<'a> From> for Body<'a> { - fn from(value: BodyTabs<'a>) -> Self { Self::Tabs(value) } -} - -impl UserData for BodyTabs<'static> { - fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("cursor", |_, me| Ok(me.cursor)); - } - - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_meta_method(MetaMethod::Len, |_, me, ()| Ok(me.items.len())); - - methods.add_meta_method(MetaMethod::Index, |_, me, idx: usize| { - if idx > me.items.len() || idx == 0 { Ok(None) } else { Ok(Some(me.items[idx - 1].clone())) } - }); - } -} - -// --- Item -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BodyTabsItem<'a> { - pub url: Cow<'a, Url>, -} - -impl<'a> From<&'a Url> for BodyTabsItem<'a> { - fn from(value: &'a Url) -> Self { Self { url: Cow::Borrowed(value) } } -} - -impl UserData for BodyTabsItem<'static> { - fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("url", |lua, me| lua.create_any_userdata(me.url.clone())); - } -} diff --git a/yazi-dds/src/body/yank.rs b/yazi-dds/src/body/yank.rs index d18c3fcf6..6213f4a2b 100644 --- a/yazi-dds/src/body/yank.rs +++ b/yazi-dds/src/body/yank.rs @@ -10,18 +10,22 @@ use super::Body; pub struct BodyYank<'a> { pub cut: bool, pub urls: Cow<'a, HashSet>, + #[serde(skip)] + dummy: bool, } impl<'a> BodyYank<'a> { #[inline] pub fn borrowed(cut: bool, urls: &'a HashSet) -> Body<'a> { - Self { cut, urls: Cow::Borrowed(urls) }.into() + Self { cut, urls: Cow::Borrowed(urls), dummy: false }.into() } } impl BodyYank<'static> { #[inline] - pub fn dummy(cut: bool) -> Body<'static> { Self { cut, urls: Default::default() }.into() } + pub fn dummy(cut: bool) -> Body<'static> { + Self { cut, urls: Default::default(), dummy: true }.into() + } } impl<'a> From> for Body<'a> { @@ -30,7 +34,7 @@ impl<'a> From> for Body<'a> { impl IntoLua<'_> for BodyYank<'static> { fn into_lua(self, lua: &Lua) -> mlua::Result> { - if let Cow::Owned(urls) = self.urls { + if let Some(Cow::Owned(urls)) = Some(self.urls).filter(|_| !self.dummy) { BodyYankIter { cut: self.cut, urls: urls.into_iter().collect() }.into_lua(lua) } else { lua.create_table_from([("cut", self.cut)])?.into_lua(lua) @@ -46,7 +50,7 @@ pub struct BodyYankIter { impl UserData for BodyYankIter { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("is_cut", |_, me| Ok(me.cut)); + fields.add_field_method_get("cut", |_, me| Ok(me.cut)); } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { diff --git a/yazi-dds/src/client.rs b/yazi-dds/src/client.rs index 4b5db8dce..649ff4977 100644 --- a/yazi-dds/src/client.rs +++ b/yazi-dds/src/client.rs @@ -53,7 +53,7 @@ impl Client { if line.starts_with("hey,") { Self::handle_hey(line); } else { - Payload::from_str(&line).map(|p| p.flush(false).emit()).ok(); + Payload::from_str(&line).map(|p| p.emit()).ok(); } } } @@ -62,7 +62,9 @@ impl Client { } #[inline] - pub(super) fn push(payload: Payload) { QUEUE.send(format!("{}\n", payload)).ok(); } + pub(super) fn push<'a>(payload: impl Into>) { + QUEUE.send(format!("{}\n", payload.into())).ok(); + } #[inline] pub(super) fn able(&self, ability: &str) -> bool { self.abilities.contains(ability) } diff --git a/yazi-dds/src/payload.rs b/yazi-dds/src/payload.rs index fdaa8ac13..217d4f679 100644 --- a/yazi-dds/src/payload.rs +++ b/yazi-dds/src/payload.rs @@ -15,40 +15,38 @@ pub struct Payload<'a> { } impl<'a> Payload<'a> { - #[inline] pub(super) fn new(body: Body<'a>) -> Self { Self { receiver: 0, severity: 0, sender: *ID, body } } - #[inline] + pub(super) fn flush(&self) { writeln!(std::io::stdout(), "{self}").ok(); } + + pub(super) fn try_flush(&self) { + let b = if self.receiver == 0 { + BOOT.remote_events.contains(self.body.kind()) + } else if let Body::Custom(b) = &self.body { + BOOT.local_events.contains(&b.kind) + } else { + false + }; + + if b { + self.flush(); + } + } + pub(super) fn with_receiver(mut self, receiver: u64) -> Self { self.receiver = receiver; self } - #[inline] pub(super) fn with_severity(mut self, severity: u8) -> Self { self.severity = severity; self } - - pub(super) fn flush(self, force: bool) -> Self { - let b = force - || if self.receiver == 0 { - BOOT.remote_events.contains(self.body.kind()) - } else if let Body::Custom(b) = &self.body { - BOOT.local_events.contains(&b.kind) - } else { - false - }; - - if b { - writeln!(std::io::stdout(), "{self}").ok(); - } - self - } } impl Payload<'static> { pub(super) fn emit(self) { + self.try_flush(); emit!(Call(Cmd::new("accept_payload").with_data(self), Layer::App)); } } @@ -76,12 +74,15 @@ impl FromStr for Payload<'_> { } } +impl<'a> From> for Payload<'a> { + fn from(value: Body<'a>) -> Self { Self::new(value) } +} + impl Display for Payload<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let result = match &self.body { Body::Hi(b) => serde_json::to_string(b), Body::Hey(b) => serde_json::to_string(b), - Body::Tabs(b) => serde_json::to_string(b), Body::Cd(b) => serde_json::to_string(b), Body::Hover(b) => serde_json::to_string(b), Body::Rename(b) => serde_json::to_string(b), diff --git a/yazi-dds/src/pubsub.rs b/yazi-dds/src/pubsub.rs index f4d33f954..023c47e7f 100644 --- a/yazi-dds/src/pubsub.rs +++ b/yazi-dds/src/pubsub.rs @@ -5,7 +5,7 @@ use parking_lot::RwLock; use yazi_boot::BOOT; use yazi_shared::{fs::Url, RoCell}; -use crate::{body::{Body, BodyCd, BodyHi, BodyHover, BodyRename, BodyTabs, BodyYank}, Client, ID, PEERS}; +use crate::{body::{Body, BodyCd, BodyHi, BodyHover, BodyRename, BodyYank}, Client, ID, PEERS}; pub static LOCAL: RoCell>>>> = RoCell::new(); @@ -65,7 +65,7 @@ impl Pubsub { unsub!(REMOTE)(plugin, kind) && Self::pub_from_hi() } - pub fn pub_(body: Body<'static>) { body.upgrade().with_receiver(*ID).flush(false).emit(); } + pub fn pub_(body: Body<'static>) { body.with_receiver(*ID).emit(); } pub fn pub_to(receiver: u64, body: Body<'static>) { if receiver == *ID { @@ -74,16 +74,16 @@ impl Pubsub { let (kind, peers) = (body.kind(), PEERS.read()); if receiver == 0 && peers.values().any(|c| c.able(kind)) { - Client::push(body.upgrade()); + Client::push(body); } else if peers.get(&receiver).is_some_and(|c| c.able(kind)) { - Client::push(body.upgrade().with_receiver(receiver)); + Client::push(body.with_receiver(receiver)); } } pub fn pub_static(severity: u8, body: Body) { let (kind, peers) = (body.kind(), PEERS.read()); if peers.values().any(|c| c.able(kind)) { - Client::push(body.upgrade().with_severity(severity)); + Client::push(body.with_severity(severity)); } } @@ -91,31 +91,19 @@ impl Pubsub { let abilities = REMOTE.read().keys().cloned().collect(); let abilities = BOOT.remote_events.union(&abilities).collect(); - Client::push(BodyHi::borrowed(abilities).upgrade()); + Client::push(BodyHi::borrowed(abilities)); true } - pub fn pub_from_tabs(tab: usize, urls: &[&Url]) { - if LOCAL.read().contains_key("tabs") { - Self::pub_(BodyTabs::dummy(tab)); - } - if PEERS.read().values().any(|p| p.able("tabs")) { - Client::push(BodyTabs::borrowed(tab, urls).upgrade()); - } - if BOOT.local_events.contains("tabs") { - BodyTabs::borrowed(tab, urls).upgrade().with_receiver(*ID).flush(true); - } - } - pub fn pub_from_cd(tab: usize, url: &Url) { if LOCAL.read().contains_key("cd") { Self::pub_(BodyCd::dummy(tab)); } if PEERS.read().values().any(|p| p.able("cd")) { - Client::push(BodyCd::borrowed(tab, url).upgrade()); + Client::push(BodyCd::borrowed(tab, url).with_severity(10)); } if BOOT.local_events.contains("cd") { - BodyCd::borrowed(tab, url).upgrade().with_receiver(*ID).flush(true); + BodyCd::borrowed(tab, url).with_receiver(*ID).flush(); } } @@ -124,10 +112,10 @@ impl Pubsub { Self::pub_(BodyHover::dummy(tab)); } if PEERS.read().values().any(|p| p.able("hover")) { - Client::push(BodyHover::borrowed(tab, url).upgrade()); + Client::push(BodyHover::borrowed(tab, url).with_severity(20)); } if BOOT.local_events.contains("hover") { - BodyHover::borrowed(tab, url).upgrade().with_receiver(*ID).flush(true); + BodyHover::borrowed(tab, url).with_receiver(*ID).flush(); } } @@ -136,10 +124,10 @@ impl Pubsub { Self::pub_(BodyRename::dummy(tab, from, to)); } if PEERS.read().values().any(|p| p.able("rename")) { - Client::push(BodyRename::borrowed(tab, from, to).upgrade()); + Client::push(BodyRename::borrowed(tab, from, to)); } if BOOT.local_events.contains("rename") { - BodyRename::borrowed(tab, from, to).upgrade().with_receiver(*ID).flush(true); + BodyRename::borrowed(tab, from, to).with_receiver(*ID).flush(); } } @@ -148,10 +136,10 @@ impl Pubsub { Self::pub_(BodyYank::dummy(cut)); } if PEERS.read().values().any(|p| p.able("yank")) { - Client::push(BodyYank::borrowed(cut, urls).upgrade()); + Client::push(BodyYank::borrowed(cut, urls).with_severity(30)); } if BOOT.local_events.contains("yank") { - BodyYank::borrowed(cut, urls).upgrade().with_receiver(*ID).flush(true); + BodyYank::borrowed(cut, urls).with_receiver(*ID).flush(); } } }