diff --git a/Cargo.lock b/Cargo.lock index d800175d..c1dd3431 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2740,6 +2740,7 @@ dependencies = [ "yazi-boot", "yazi-config", "yazi-plugin", + "yazi-proxy", "yazi-scheduler", "yazi-shared", ] @@ -2770,6 +2771,7 @@ dependencies = [ "yazi-config", "yazi-core", "yazi-plugin", + "yazi-proxy", "yazi-scheduler", "yazi-shared", ] @@ -2801,6 +2803,7 @@ dependencies = [ "yazi-boot", "yazi-config", "yazi-prebuild", + "yazi-proxy", "yazi-shared", ] @@ -2810,6 +2813,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4b6c8e12e39ac0f79fa96f36e5b88e0da8d230691abd729eec709b43c74f632" +[[package]] +name = "yazi-proxy" +version = "0.2.3" +dependencies = [ + "anyhow", + "tokio", + "yazi-config", + "yazi-shared", +] + [[package]] name = "yazi-scheduler" version = "0.2.3" @@ -2828,6 +2841,7 @@ dependencies = [ "yazi-adaptor", "yazi-config", "yazi-plugin", + "yazi-proxy", "yazi-shared", ] diff --git a/yazi-config/src/popup/origin.rs b/yazi-config/src/popup/origin.rs index ac997ecf..70231c88 100644 --- a/yazi-config/src/popup/origin.rs +++ b/yazi-config/src/popup/origin.rs @@ -1,24 +1,63 @@ +use std::{fmt::Display, str::FromStr}; + +use anyhow::bail; use serde::Deserialize; #[derive(Clone, Copy, Default, Deserialize, PartialEq, Eq)] +#[serde(try_from = "String")] pub enum Origin { #[default] - #[serde(rename = "top-left")] TopLeft, - #[serde(rename = "top-center")] TopCenter, - #[serde(rename = "top-right")] TopRight, - #[serde(rename = "bottom-left")] BottomLeft, - #[serde(rename = "bottom-center")] BottomCenter, - #[serde(rename = "bottom-right")] BottomRight, - #[serde(rename = "center")] Center, - #[serde(rename = "hovered")] Hovered, } + +impl FromStr for Origin { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + Ok(match s { + "top-left" => Self::TopLeft, + "top-center" => Self::TopCenter, + "top-right" => Self::TopRight, + + "bottom-left" => Self::BottomLeft, + "bottom-center" => Self::BottomCenter, + "bottom-right" => Self::BottomRight, + + "center" => Self::Center, + "hovered" => Self::Hovered, + _ => bail!("Invalid `origin` value: {s}"), + }) + } +} + +impl TryFrom for Origin { + type Error = anyhow::Error; + + fn try_from(value: String) -> Result { Self::from_str(&value) } +} + +impl Display for Origin { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::TopLeft => "top-left", + Self::TopCenter => "top-center", + Self::TopRight => "top-right", + + Self::BottomLeft => "bottom-left", + Self::BottomCenter => "bottom-center", + Self::BottomRight => "bottom-right", + + Self::Center => "center", + Self::Hovered => "hovered", + }) + } +} diff --git a/yazi-config/src/which/sorting.rs b/yazi-config/src/which/sorting.rs index cb38e803..73939d58 100644 --- a/yazi-config/src/which/sorting.rs +++ b/yazi-config/src/which/sorting.rs @@ -20,7 +20,7 @@ impl FromStr for SortBy { "none" => Self::None, "key" => Self::Key, "desc" => Self::Desc, - _ => bail!("Invalid sort option: {s}"), + _ => bail!("Invalid `sort_by` value: {s}"), }) } } diff --git a/yazi-core/Cargo.toml b/yazi-core/Cargo.toml index f6175b7b..c96dc59b 100644 --- a/yazi-core/Cargo.toml +++ b/yazi-core/Cargo.toml @@ -13,6 +13,7 @@ yazi-adaptor = { path = "../yazi-adaptor", version = "0.2.3" } yazi-boot = { path = "../yazi-boot", version = "0.2.3" } yazi-config = { path = "../yazi-config", version = "0.2.3" } yazi-plugin = { path = "../yazi-plugin", version = "0.2.3" } +yazi-proxy = { path = "../yazi-proxy", version = "0.2.3" } yazi-scheduler = { path = "../yazi-scheduler", version = "0.2.3" } yazi-shared = { path = "../yazi-shared", version = "0.2.3" } diff --git a/yazi-core/src/completion/commands/close.rs b/yazi-core/src/completion/commands/close.rs index 91fe0934..a884587a 100644 --- a/yazi-core/src/completion/commands/close.rs +++ b/yazi-core/src/completion/commands/close.rs @@ -1,6 +1,7 @@ -use yazi_shared::{emit, event::Cmd, render, Layer}; +use yazi_proxy::InputProxy; +use yazi_shared::{event::Cmd, render}; -use crate::{completion::Completion, input::Input}; +use crate::completion::Completion; pub struct Opt { submit: bool, @@ -11,16 +12,11 @@ impl From for Opt { } impl Completion { - #[inline] - pub fn _close() { - emit!(Call(Cmd::new("close"), Layer::Completion)); - } - pub fn close(&mut self, opt: impl Into) { let opt = opt.into() as Opt; if let Some(s) = self.selected().filter(|_| opt.submit) { - Input::_complete(s, self.ticket); + InputProxy::complete(s, self.ticket); } self.caches.clear(); diff --git a/yazi-core/src/completion/commands/trigger.rs b/yazi-core/src/completion/commands/trigger.rs index f8389190..84fea5dd 100644 --- a/yazi-core/src/completion/commands/trigger.rs +++ b/yazi-core/src/completion/commands/trigger.rs @@ -20,14 +20,6 @@ impl From for Opt { } impl Completion { - #[inline] - pub fn _trigger(word: &str, ticket: usize) { - emit!(Call( - Cmd::args("trigger", vec![word.to_owned()]).with("ticket", ticket), - Layer::Completion - )); - } - pub fn trigger(&mut self, opt: impl Into) { let opt = opt.into() as Opt; if opt.ticket < self.ticket { diff --git a/yazi-core/src/folder/folder.rs b/yazi-core/src/folder/folder.rs index c032d5f7..e04daa97 100644 --- a/yazi-core/src/folder/folder.rs +++ b/yazi-core/src/folder/folder.rs @@ -2,10 +2,11 @@ use std::{mem, time::SystemTime}; use ratatui::layout::Rect; use yazi_config::{LAYOUT, MANAGER}; +use yazi_proxy::ManagerProxy; use yazi_shared::fs::{File, FilesOp, Url}; use super::FolderStage; -use crate::{folder::Files, manager::Manager, Step}; +use crate::{folder::Files, Step}; #[derive(Default)] pub struct Folder { @@ -99,7 +100,7 @@ impl Folder { let new = self.cursor / limit; if mem::replace(&mut self.page, new) != new || force { - Manager::_update_paged_by(new, &self.cwd); + ManagerProxy::update_paged_by(new, &self.cwd); } } diff --git a/yazi-core/src/input/commands/close.rs b/yazi-core/src/input/commands/close.rs index a882b411..38e6c215 100644 --- a/yazi-core/src/input/commands/close.rs +++ b/yazi-core/src/input/commands/close.rs @@ -1,6 +1,7 @@ +use yazi_proxy::CompletionProxy; use yazi_shared::{event::Cmd, render, InputError}; -use crate::{completion::Completion, input::Input}; +use crate::input::Input; pub struct Opt { submit: bool, @@ -18,7 +19,7 @@ impl Input { let opt = opt.into() as Opt; if self.completion { - Completion::_close(); + CompletionProxy::close(); } if let Some(cb) = self.callback.take() { diff --git a/yazi-core/src/input/commands/complete.rs b/yazi-core/src/input/commands/complete.rs index e0dcc3a3..64686b92 100644 --- a/yazi-core/src/input/commands/complete.rs +++ b/yazi-core/src/input/commands/complete.rs @@ -1,6 +1,6 @@ use std::path::MAIN_SEPARATOR; -use yazi_shared::{emit, event::Cmd, render, Layer}; +use yazi_shared::{event::Cmd, render}; use crate::input::Input; @@ -19,11 +19,6 @@ impl From for Opt { } impl Input { - #[inline] - pub fn _complete(word: &str, ticket: usize) { - emit!(Call(Cmd::args("complete", vec![word.to_owned()]).with("ticket", ticket), Layer::Input)); - } - pub fn complete(&mut self, opt: impl Into) { let opt = opt.into() as Opt; if self.ticket != opt.ticket { diff --git a/yazi-core/src/input/commands/escape.rs b/yazi-core/src/input/commands/escape.rs index b2700837..cd0ab484 100644 --- a/yazi-core/src/input/commands/escape.rs +++ b/yazi-core/src/input/commands/escape.rs @@ -1,6 +1,7 @@ +use yazi_proxy::CompletionProxy; use yazi_shared::{event::Cmd, render}; -use crate::{completion::Completion, input::{op::InputOp, Input, InputMode}}; +use crate::input::{op::InputOp, Input, InputMode}; pub struct Opt; @@ -26,7 +27,7 @@ impl Input { self.move_(-1); if self.completion { - Completion::_close(); + CompletionProxy::close(); } } } diff --git a/yazi-core/src/input/commands/show.rs b/yazi-core/src/input/commands/show.rs index f6b4b30f..bc35e16e 100644 --- a/yazi-core/src/input/commands/show.rs +++ b/yazi-core/src/input/commands/show.rs @@ -1,28 +1,10 @@ -use tokio::sync::mpsc; -use yazi_config::popup::InputCfg; -use yazi_shared::{emit, event::Cmd, render, InputError, Layer}; +use yazi_proxy::InputOpt; +use yazi_shared::render; use crate::input::Input; -pub struct Opt { - cfg: InputCfg, - tx: mpsc::UnboundedSender>, -} - -impl TryFrom for Opt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} - impl Input { - pub fn _show(cfg: InputCfg) -> mpsc::UnboundedReceiver> { - let (tx, rx) = mpsc::unbounded_channel(); - emit!(Call(Cmd::new("show").with_data(Opt { cfg, tx }), Layer::Input)); - rx - } - - pub fn show(&mut self, opt: impl TryInto) { + pub fn show(&mut self, opt: impl TryInto) { let Ok(opt) = opt.try_into() else { return; }; diff --git a/yazi-core/src/manager/commands/create.rs b/yazi-core/src/manager/commands/create.rs index c4629302..8779a2af 100644 --- a/yazi-core/src/manager/commands/create.rs +++ b/yazi-core/src/manager/commands/create.rs @@ -2,9 +2,10 @@ use std::path::PathBuf; use tokio::fs; use yazi_config::popup::InputCfg; +use yazi_proxy::{InputProxy, ManagerProxy}; use yazi_shared::{event::Cmd, fs::{File, FilesOp, Url}}; -use crate::{input::Input, manager::Manager}; +use crate::manager::Manager; pub struct Opt { force: bool, @@ -19,14 +20,14 @@ impl Manager { let opt = opt.into() as Opt; let cwd = self.cwd().to_owned(); tokio::spawn(async move { - let mut result = Input::_show(InputCfg::create()); + let mut result = InputProxy::show(InputCfg::create()); let Some(Ok(name)) = result.recv().await else { return Ok(()); }; let path = cwd.join(&name); if !opt.force && fs::symlink_metadata(&path).await.is_ok() { - match Input::_show(InputCfg::overwrite()).recv().await { + match InputProxy::show(InputCfg::overwrite()).recv().await { Some(Ok(c)) if c == "y" || c == "Y" => (), _ => return Ok(()), } @@ -43,7 +44,7 @@ impl Manager { Url::from(path.components().take(cwd.components().count() + 1).collect::()); if let Ok(f) = File::from(child.clone()).await { FilesOp::Creating(cwd, vec![f]).emit(); - Manager::_hover(Some(child)); + ManagerProxy::hover(Some(child)); } Ok::<(), anyhow::Error>(()) }); diff --git a/yazi-core/src/manager/commands/hover.rs b/yazi-core/src/manager/commands/hover.rs index b1b2d005..4d46e1b8 100644 --- a/yazi-core/src/manager/commands/hover.rs +++ b/yazi-core/src/manager/commands/hover.rs @@ -1,6 +1,6 @@ use std::collections::BTreeSet; -use yazi_shared::{emit, event::Cmd, fs::Url, render, Layer}; +use yazi_shared::{event::Cmd, fs::Url, render}; use crate::manager::Manager; @@ -16,14 +16,6 @@ impl From> for Opt { } impl Manager { - #[inline] - pub fn _hover(url: Option) { - emit!(Call( - Cmd::args("hover", url.map_or_else(Vec::new, |u| vec![u.to_string()])), - Layer::Manager - )); - } - pub fn hover(&mut self, opt: impl Into) { let opt = opt.into() as Opt; diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index 34dae598..c62b31ba 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -4,9 +4,10 @@ use tracing::error; use yazi_boot::ARGS; use yazi_config::{popup::SelectCfg, OPEN}; use yazi_plugin::isolate; -use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, Layer, MIME_DIR}; +use yazi_proxy::{ManagerProxy, OpenDoOpt, TasksProxy}; +use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, MIME_DIR}; -use crate::{folder::Folder, manager::Manager, select::Select, tasks::Tasks}; +use crate::{folder::Folder, manager::Manager, tasks::Tasks}; pub struct Opt { interactive: bool, @@ -22,17 +23,6 @@ impl From for Opt { } } -#[derive(Default)] -pub struct OptDo { - hovered: Url, - targets: Vec<(Url, String)>, - interactive: bool, -} - -impl From for OptDo { - fn from(mut c: Cmd) -> Self { c.take_data().unwrap_or_default() } -} - impl Manager { pub fn open(&mut self, opt: impl Into, tasks: &Tasks) { if !self.active_mut().try_escape_visual() { @@ -50,7 +40,7 @@ impl Manager { let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]); for u in selected { - if self.mimetype.get(u).is_some() { + if self.mimetype.contains_key(u) { done.push((u.clone(), String::new())); } else if self.guess_folder(u) { done.push((u.clone(), MIME_DIR.to_owned())); @@ -60,7 +50,8 @@ impl Manager { } if todo.is_empty() { - return self.open_do(OptDo { hovered, targets: done, interactive: opt.interactive }, tasks); + return self + .open_do(OpenDoOpt { hovered, targets: done, interactive: opt.interactive }, tasks); } tokio::spawn(async move { @@ -76,17 +67,12 @@ impl Manager { error!("preload in open failed: {e}"); } - Self::_open_do(OptDo { hovered, targets: done, interactive: opt.interactive }); + ManagerProxy::open_do(OpenDoOpt { hovered, targets: done, interactive: opt.interactive }); }); } - #[inline] - pub fn _open_do(opt: OptDo) { - emit!(Call(Cmd::new("open_do").with_data(opt), Layer::Manager)); - } - - pub fn open_do(&mut self, opt: impl Into, tasks: &Tasks) { - let opt = opt.into() as OptDo; + pub fn open_do(&mut self, opt: impl Into, tasks: &Tasks) { + let opt = opt.into() as OpenDoOpt; let targets: Vec<_> = opt .targets .into_iter() @@ -108,9 +94,11 @@ impl Manager { let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect(); tokio::spawn(async move { - let result = Select::_show(SelectCfg::open(openers.iter().map(|o| o.desc.clone()).collect())); + let result = yazi_proxy::SelectProxy::show(SelectCfg::open( + openers.iter().map(|o| o.desc.clone()).collect(), + )); if let Ok(choice) = result.await { - Tasks::_open_with(urls, openers[choice].clone()); + TasksProxy::open_with(urls, openers[choice].clone()); } }); } diff --git a/yazi-core/src/manager/commands/peek.rs b/yazi-core/src/manager/commands/peek.rs index df6d8304..217c0067 100644 --- a/yazi-core/src/manager/commands/peek.rs +++ b/yazi-core/src/manager/commands/peek.rs @@ -1,4 +1,4 @@ -use yazi_shared::{emit, event::Cmd, fs::Url, render, Layer}; +use yazi_shared::{event::Cmd, fs::Url, render}; use crate::manager::Manager; @@ -25,11 +25,6 @@ impl From for Opt { } impl Manager { - #[inline] - pub fn _peek(force: bool) { - emit!(Call(Cmd::new("peek").with_bool("force", force), Layer::Manager)); - } - pub fn peek(&mut self, opt: impl Into) { let Some(hovered) = self.hovered().cloned() else { return render!(self.active_mut().preview.reset()); diff --git a/yazi-core/src/manager/commands/quit.rs b/yazi-core/src/manager/commands/quit.rs index 30119aa5..7fd09b27 100644 --- a/yazi-core/src/manager/commands/quit.rs +++ b/yazi-core/src/manager/commands/quit.rs @@ -1,7 +1,8 @@ use yazi_config::popup::InputCfg; +use yazi_proxy::InputProxy; use yazi_shared::{emit, event::{Cmd, EventQuit}}; -use crate::{input::Input, manager::Manager, tasks::Tasks}; +use crate::{manager::Manager, tasks::Tasks}; #[derive(Default)] pub struct Opt { @@ -25,7 +26,7 @@ impl Manager { } tokio::spawn(async move { - let mut result = Input::_show(InputCfg::quit(tasks)); + let mut result = InputProxy::show(InputCfg::quit(tasks)); if let Some(Ok(choice)) = result.recv().await { if choice == "y" || choice == "Y" { emit!(Quit(opt)); diff --git a/yazi-core/src/manager/commands/refresh.rs b/yazi-core/src/manager/commands/refresh.rs index 5af0999e..2b8c8e29 100644 --- a/yazi-core/src/manager/commands/refresh.rs +++ b/yazi-core/src/manager/commands/refresh.rs @@ -1,15 +1,10 @@ use std::env; -use yazi_shared::{emit, event::Cmd, Layer}; +use yazi_shared::event::Cmd; use crate::{manager::Manager, tasks::Tasks}; impl Manager { - #[inline] - pub fn _refresh() { - emit!(Call(Cmd::new("refresh"), Layer::Manager)); - } - pub fn refresh(&mut self, _: Cmd, tasks: &Tasks) { env::set_current_dir(self.cwd()).ok(); env::set_var("PWD", self.cwd()); diff --git a/yazi-core/src/manager/commands/remove.rs b/yazi-core/src/manager/commands/remove.rs index 00703383..5ccfc112 100644 --- a/yazi-core/src/manager/commands/remove.rs +++ b/yazi-core/src/manager/commands/remove.rs @@ -1,7 +1,8 @@ use yazi_config::popup::InputCfg; -use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; +use yazi_proxy::{InputProxy, ManagerProxy}; +use yazi_shared::{event::Cmd, fs::Url}; -use crate::{input::Input, manager::Manager, tasks::Tasks}; +use crate::{manager::Manager, tasks::Tasks}; pub struct Opt { force: bool, @@ -33,7 +34,7 @@ impl Manager { } tokio::spawn(async move { - let mut result = Input::_show(if opt.permanently { + let mut result = InputProxy::show(if opt.permanently { InputCfg::delete(opt.targets.len()) } else { InputCfg::trash(opt.targets.len()) @@ -44,19 +45,11 @@ impl Manager { return; } - Self::_remove_do(opt.targets, opt.permanently); + ManagerProxy::remove_do(opt.targets, opt.permanently); } }); } - #[inline] - pub fn _remove_do(targets: Vec, permanently: bool) { - emit!(Call( - Cmd::new("remove_do").with_bool("permanently", permanently).with_data(targets), - Layer::Manager - )); - } - pub fn remove_do(&mut self, opt: impl Into, tasks: &Tasks) { let opt = opt.into() as Opt; for u in &opt.targets { diff --git a/yazi-core/src/manager/commands/rename.rs b/yazi-core/src/manager/commands/rename.rs index fd53d416..68f63f1b 100644 --- a/yazi-core/src/manager/commands/rename.rs +++ b/yazi-core/src/manager/commands/rename.rs @@ -4,10 +4,11 @@ use anyhow::{anyhow, bail, Result}; use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}}; use yazi_config::{popup::InputCfg, OPEN, PREVIEW}; use yazi_plugin::external::{self, ShellOpt}; -use yazi_scheduler::{Scheduler, BLOCKER}; +use yazi_proxy::{AppProxy, InputProxy, ManagerProxy}; +use yazi_scheduler::BLOCKER; use yazi_shared::{event::Cmd, fs::{max_common_root, File, FilesOp, Url}, term::Term, Defer}; -use crate::{input::Input, manager::Manager}; +use crate::manager::Manager; pub struct Opt { force: bool, @@ -49,7 +50,7 @@ impl Manager { let file = File::from(new.clone()).await?; FilesOp::Deleting(file.parent().unwrap(), vec![new.clone()]).emit(); FilesOp::Upserting(file.parent().unwrap(), BTreeMap::from_iter([(old, file)])).emit(); - Ok(Self::_hover(Some(new))) + Ok(ManagerProxy::hover(Some(new))) } pub fn rename(&mut self, opt: impl Into) { @@ -77,7 +78,7 @@ impl Manager { }; tokio::spawn(async move { - let mut result = Input::_show(InputCfg::rename().with_value(name).with_cursor(cursor)); + let mut result = InputProxy::show(InputCfg::rename().with_value(name).with_cursor(cursor)); let Some(Ok(name)) = result.recv().await else { return; }; @@ -88,7 +89,7 @@ impl Manager { return; } - let mut result = Input::_show(InputCfg::overwrite()); + let mut result = InputProxy::show(InputCfg::overwrite()); if let Some(Ok(choice)) = result.recv().await { if choice == "y" || choice == "Y" { Self::rename_and_hover(hovered, Url::from(new)).await.ok(); @@ -122,10 +123,10 @@ impl Manager { let _guard = BLOCKER.acquire().await.unwrap(); let _defer = Defer::new(|| { - Scheduler::app_resume(); + AppProxy::resume(); tokio::spawn(fs::remove_file(tmp.clone())) }); - Scheduler::app_stop().await; + AppProxy::stop().await; let mut child = external::shell(ShellOpt { cmd: (*opener.exec).into(), diff --git a/yazi-core/src/manager/commands/suspend.rs b/yazi-core/src/manager/commands/suspend.rs index 429d11e8..ffb0bee0 100644 --- a/yazi-core/src/manager/commands/suspend.rs +++ b/yazi-core/src/manager/commands/suspend.rs @@ -1,4 +1,4 @@ -use yazi_scheduler::Scheduler; +use yazi_proxy::AppProxy; use yazi_shared::event::Cmd; use crate::manager::Manager; @@ -7,7 +7,7 @@ impl Manager { pub fn suspend(&mut self, _: Cmd) { #[cfg(unix)] tokio::spawn(async move { - Scheduler::app_stop().await; + AppProxy::stop().await; unsafe { libc::raise(libc::SIGTSTP) }; }); } diff --git a/yazi-core/src/manager/commands/update_files.rs b/yazi-core/src/manager/commands/update_files.rs index 120505c8..7da81b19 100644 --- a/yazi-core/src/manager/commands/update_files.rs +++ b/yazi-core/src/manager/commands/update_files.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; +use yazi_proxy::ManagerProxy; use yazi_shared::{event::Cmd, fs::FilesOp, render}; use crate::{folder::Folder, manager::Manager, tab::Tab, tasks::Tasks}; @@ -56,8 +57,8 @@ impl Manager { return; } - Self::_hover(None); // Re-hover in next loop - Self::_update_paged(); // Update for paged files in next loop + ManagerProxy::hover(None); // Re-hover in next loop + ManagerProxy::update_paged(); // Update for paged files in next loop if calc { tasks.preload_sorted(&tab.current.files); } @@ -73,7 +74,7 @@ impl Manager { } if !foreign { - Self::_peek(true); + ManagerProxy::peek(true); } } diff --git a/yazi-core/src/manager/commands/update_paged.rs b/yazi-core/src/manager/commands/update_paged.rs index c3c16498..fea90818 100644 --- a/yazi-core/src/manager/commands/update_paged.rs +++ b/yazi-core/src/manager/commands/update_paged.rs @@ -1,4 +1,4 @@ -use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; +use yazi_shared::{event::Cmd, fs::Url}; use crate::{manager::Manager, tasks::Tasks}; @@ -22,19 +22,6 @@ impl From<()> for Opt { } impl Manager { - #[inline] - pub fn _update_paged() { - emit!(Call(Cmd::new("update_paged"), Layer::Manager)); - } - - #[inline] - pub fn _update_paged_by(page: usize, only_if: &Url) { - emit!(Call( - Cmd::args("update_paged", vec![page.to_string()]).with("only-if", only_if.to_string()), - Layer::Manager - )); - } - pub fn update_paged(&mut self, opt: impl TryInto, tasks: &Tasks) { let Ok(opt) = opt.try_into() else { return; diff --git a/yazi-core/src/manager/tabs.rs b/yazi-core/src/manager/tabs.rs index fb60b6b8..5be02930 100644 --- a/yazi-core/src/manager/tabs.rs +++ b/yazi-core/src/manager/tabs.rs @@ -1,9 +1,10 @@ use std::ops::{Deref, DerefMut}; use yazi_boot::BOOT; +use yazi_proxy::ManagerProxy; use yazi_shared::fs::Url; -use crate::{manager::Manager, tab::Tab}; +use crate::tab::Tab; pub struct Tabs { pub idx: usize, @@ -17,7 +18,7 @@ impl Tabs { tabs.items[0].reveal(Url::from(BOOT.cwd.join(file))); } - Manager::_refresh(); + ManagerProxy::refresh(); tabs } @@ -42,8 +43,8 @@ impl Tabs { } self.idx = idx; - Manager::_refresh(); - Manager::_peek(true); + ManagerProxy::refresh(); + ManagerProxy::peek(true); } } diff --git a/yazi-core/src/notify/commands/push.rs b/yazi-core/src/notify/commands/push.rs index 778241ea..f3f2572b 100644 --- a/yazi-core/src/notify/commands/push.rs +++ b/yazi-core/src/notify/commands/push.rs @@ -5,18 +5,6 @@ use yazi_shared::{emit, event::Cmd, Layer}; use crate::notify::{Message, Notify}; impl Notify { - #[inline] - pub fn _push_warn(title: &str, content: &str) { - emit!(Call( - Cmd::new("notify") - .with("title", title) - .with("content", content) - .with("level", "warn") - .with("timeout", 5), - Layer::App - )); - } - pub fn push(&mut self, msg: impl TryInto) { let Ok(mut msg) = msg.try_into() else { return; diff --git a/yazi-core/src/select/commands/show.rs b/yazi-core/src/select/commands/show.rs index 85c79878..b43157e1 100644 --- a/yazi-core/src/select/commands/show.rs +++ b/yazi-core/src/select/commands/show.rs @@ -1,29 +1,10 @@ -use anyhow::Result; -use tokio::sync::oneshot; -use yazi_config::popup::SelectCfg; -use yazi_shared::{emit, event::Cmd, render, term::Term, Layer}; +use yazi_proxy::SelectOpt; +use yazi_shared::render; use crate::select::Select; -pub struct Opt { - cfg: SelectCfg, - tx: oneshot::Sender>, -} - -impl TryFrom for Opt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} - impl Select { - pub async fn _show(cfg: SelectCfg) -> Result { - let (tx, rx) = oneshot::channel(); - emit!(Call(Cmd::new("show").with_data(Opt { cfg, tx }), Layer::Select)); - rx.await.unwrap_or_else(|_| Term::goodbye(|| false)) - } - - pub fn show(&mut self, opt: impl TryInto) { + pub fn show(&mut self, opt: impl TryInto) { let Ok(opt) = opt.try_into() else { return; }; diff --git a/yazi-core/src/tab/commands/arrow.rs b/yazi-core/src/tab/commands/arrow.rs index be846ea5..4fa92e93 100644 --- a/yazi-core/src/tab/commands/arrow.rs +++ b/yazi-core/src/tab/commands/arrow.rs @@ -1,6 +1,7 @@ +use yazi_proxy::ManagerProxy; use yazi_shared::{event::Cmd, render}; -use crate::{manager::Manager, tab::Tab, Step}; +use crate::{tab::Tab, Step}; pub struct Opt { step: Step, @@ -36,7 +37,7 @@ impl Tab { } } - Manager::_hover(None); + ManagerProxy::hover(None); render!(); } } diff --git a/yazi-core/src/tab/commands/cd.rs b/yazi-core/src/tab/commands/cd.rs index 8f0a4aad..a5cf6a84 100644 --- a/yazi-core/src/tab/commands/cd.rs +++ b/yazi-core/src/tab/commands/cd.rs @@ -3,9 +3,10 @@ use std::{mem, time::Duration}; use tokio::{fs, pin}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use yazi_config::popup::InputCfg; -use yazi_shared::{emit, event::Cmd, fs::{expand_path, Url}, render, Debounce, InputError, Layer}; +use yazi_proxy::{CompletionProxy, InputProxy, ManagerProxy, TabProxy}; +use yazi_shared::{event::Cmd, fs::{expand_path, Url}, render, Debounce, InputError}; -use crate::{completion::Completion, input::Input, manager::Manager, tab::Tab}; +use crate::tab::Tab; pub struct Opt { target: Url, @@ -27,11 +28,6 @@ impl From for Opt { } impl Tab { - #[inline] - pub fn _cd(target: &Url) { - emit!(Call(Cmd::args("cd", vec![target.to_string()]), Layer::Manager)); - } - pub fn cd(&mut self, opt: impl Into) { if !self.try_escape_visual() { return; @@ -68,13 +64,13 @@ impl Tab { self.backstack.push(opt.target.clone()); } - Manager::_refresh(); + ManagerProxy::refresh(); render!(); } fn cd_interactive(&mut self) { tokio::spawn(async move { - let rx = Input::_show(InputCfg::cd()); + let rx = InputProxy::show(InputCfg::cd()); let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50)); pin!(rx); @@ -88,13 +84,13 @@ impl Tab { }; if meta.is_dir() { - Tab::_cd(&u); + TabProxy::cd(&u); } else { - Tab::_reveal(&u); + TabProxy::reveal(&u); } } Err(InputError::Completed(before, ticket)) => { - Completion::_trigger(&before, ticket); + CompletionProxy::trigger(&before, ticket); } _ => break, } diff --git a/yazi-core/src/tab/commands/escape.rs b/yazi-core/src/tab/commands/escape.rs index df142452..bd76c4a2 100644 --- a/yazi-core/src/tab/commands/escape.rs +++ b/yazi-core/src/tab/commands/escape.rs @@ -1,7 +1,8 @@ use bitflags::bitflags; +use yazi_proxy::{AppProxy, ManagerProxy}; use yazi_shared::{event::Cmd, render, render_and}; -use crate::{manager::Manager, notify::Notify, tab::Tab}; +use crate::tab::Tab; bitflags! { pub struct Opt: u8 { @@ -74,7 +75,7 @@ impl Tab { self.selected.clear(); if self.current.hovered().is_some_and(|h| h.is_dir()) { - Manager::_peek(true); + ManagerProxy::peek(true); } render_and!(true) } @@ -110,7 +111,7 @@ impl Tab { if !select { self.selected.remove_many(&urls); } else if self.selected.add_many(&urls) != urls.len() { - Notify::_push_warn( + AppProxy::warn( "Escape visual mode", "Some files cannot be selected, due to path nesting conflict.", ); diff --git a/yazi-core/src/tab/commands/filter.rs b/yazi-core/src/tab/commands/filter.rs index c2e21faf..718a0828 100644 --- a/yazi-core/src/tab/commands/filter.rs +++ b/yazi-core/src/tab/commands/filter.rs @@ -3,9 +3,10 @@ use std::time::Duration; use tokio::pin; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use yazi_config::popup::InputCfg; +use yazi_proxy::{InputProxy, ManagerProxy}; use yazi_shared::{emit, event::Cmd, render, Debounce, InputError, Layer}; -use crate::{folder::{Filter, FilterCase}, input::Input, manager::Manager, tab::Tab}; +use crate::{folder::{Filter, FilterCase}, tab::Tab}; #[derive(Default)] pub struct Opt { @@ -28,7 +29,7 @@ impl Tab { pub fn filter(&mut self, opt: impl Into) { let opt = opt.into() as Opt; tokio::spawn(async move { - let rx = Input::_show(InputCfg::filter()); + let rx = InputProxy::show(InputCfg::filter()); let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50)); pin!(rx); @@ -62,7 +63,7 @@ impl Tab { }; if opt.done { - Manager::_update_paged(); // Update for paged files in next loop + ManagerProxy::update_paged(); // Update for paged files in next loop } let hovered = self.current.hovered().map(|f| f.url()); @@ -71,7 +72,7 @@ impl Tab { } if self.current.repos(hovered) { - Manager::_hover(None); + ManagerProxy::hover(None); } render!(); } diff --git a/yazi-core/src/tab/commands/find.rs b/yazi-core/src/tab/commands/find.rs index a506d558..950a73cc 100644 --- a/yazi-core/src/tab/commands/find.rs +++ b/yazi-core/src/tab/commands/find.rs @@ -3,9 +3,10 @@ use std::time::Duration; use tokio::pin; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use yazi_config::popup::InputCfg; +use yazi_proxy::InputProxy; use yazi_shared::{emit, event::Cmd, render, Debounce, InputError, Layer}; -use crate::{folder::FilterCase, input::Input, tab::{Finder, Tab}}; +use crate::{folder::FilterCase, tab::{Finder, Tab}}; pub struct Opt { query: Option, @@ -35,7 +36,7 @@ impl Tab { pub fn find(&mut self, opt: impl Into) { let opt = opt.into() as Opt; tokio::spawn(async move { - let rx = Input::_show(InputCfg::find(opt.prev)); + let rx = InputProxy::show(InputCfg::find(opt.prev)); let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50)); pin!(rx); diff --git a/yazi-core/src/tab/commands/hidden.rs b/yazi-core/src/tab/commands/hidden.rs index 93c2e3b4..6e71d8d2 100644 --- a/yazi-core/src/tab/commands/hidden.rs +++ b/yazi-core/src/tab/commands/hidden.rs @@ -1,6 +1,7 @@ +use yazi_proxy::ManagerProxy; use yazi_shared::event::Cmd; -use crate::{manager::Manager, tab::Tab}; +use crate::tab::Tab; impl Tab { pub fn hidden(&mut self, c: Cmd) { @@ -14,10 +15,10 @@ impl Tab { self.apply_files_attrs(); if hovered.as_ref() != self.current.hovered().map(|f| &f.url) { - Manager::_hover(hovered); + ManagerProxy::hover(hovered); } else if self.current.hovered().is_some_and(|f| f.is_dir()) { - Manager::_peek(true); + ManagerProxy::peek(true); } - Manager::_update_paged(); + ManagerProxy::update_paged(); } } diff --git a/yazi-core/src/tab/commands/jump.rs b/yazi-core/src/tab/commands/jump.rs index c282205d..e4df1ff2 100644 --- a/yazi-core/src/tab/commands/jump.rs +++ b/yazi-core/src/tab/commands/jump.rs @@ -1,5 +1,6 @@ use yazi_plugin::external::{self, FzfOpt, ZoxideOpt}; -use yazi_scheduler::{Scheduler, BLOCKER}; +use yazi_proxy::{AppProxy, TabProxy}; +use yazi_scheduler::BLOCKER; use yazi_shared::{event::Cmd, fs::ends_with_slash, Defer}; use crate::tab::Tab; @@ -37,8 +38,8 @@ impl Tab { let cwd = self.current.cwd.clone(); tokio::spawn(async move { let _guard = BLOCKER.acquire().await.unwrap(); - let _defer = Defer::new(Scheduler::app_resume); - Scheduler::app_stop().await; + let _defer = Defer::new(AppProxy::resume); + AppProxy::stop().await; let result = if opt.type_ == OptType::Fzf { external::fzf(FzfOpt { cwd }).await @@ -51,9 +52,9 @@ impl Tab { }; if opt.type_ == OptType::Fzf && !ends_with_slash(&url) { - Tab::_reveal(&url) + TabProxy::reveal(&url) } else { - Tab::_cd(&url) + TabProxy::cd(&url) } }); } diff --git a/yazi-core/src/tab/commands/reveal.rs b/yazi-core/src/tab/commands/reveal.rs index bb52364b..cf49d736 100644 --- a/yazi-core/src/tab/commands/reveal.rs +++ b/yazi-core/src/tab/commands/reveal.rs @@ -1,6 +1,7 @@ -use yazi_shared::{emit, event::Cmd, fs::{expand_path, File, FilesOp, Url}, Layer}; +use yazi_proxy::ManagerProxy; +use yazi_shared::{event::Cmd, fs::{expand_path, File, FilesOp, Url}}; -use crate::{manager::Manager, tab::Tab}; +use crate::tab::Tab; pub struct Opt { target: Url, @@ -21,11 +22,6 @@ impl From for Opt { } impl Tab { - #[inline] - pub fn _reveal(target: &Url) { - emit!(Call(Cmd::args("reveal", vec![target.to_string()]), Layer::Manager)); - } - pub fn reveal(&mut self, opt: impl Into) { let opt = opt.into() as Opt; @@ -35,6 +31,6 @@ impl Tab { self.cd(parent.clone()); FilesOp::Creating(parent, vec![File::from_dummy(&opt.target)]).emit(); - Manager::_hover(Some(opt.target)); + ManagerProxy::hover(Some(opt.target)); } } diff --git a/yazi-core/src/tab/commands/search.rs b/yazi-core/src/tab/commands/search.rs index c940e3a6..4f71ffc0 100644 --- a/yazi-core/src/tab/commands/search.rs +++ b/yazi-core/src/tab/commands/search.rs @@ -5,9 +5,10 @@ use tokio::pin; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use yazi_config::popup::InputCfg; use yazi_plugin::external; +use yazi_proxy::{InputProxy, ManagerProxy, TabProxy}; use yazi_shared::{event::Cmd, fs::FilesOp, render}; -use crate::{input::Input, manager::Manager, tab::Tab}; +use crate::tab::Tab; #[derive(PartialEq, Eq)] pub enum OptType { @@ -59,7 +60,7 @@ impl Tab { let hidden = self.conf.show_hidden; self.search = Some(tokio::spawn(async move { - let mut input = Input::_show(InputCfg::search(&opt.type_.to_string())); + let mut input = InputProxy::show(InputCfg::search(&opt.type_.to_string())); let Some(Ok(subject)) = input.recv().await else { bail!("") }; cwd = cwd.into_search(subject.clone()); @@ -72,7 +73,7 @@ impl Tab { let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(300)); pin!(rx); - let ((), ticket) = (Tab::_cd(&cwd), FilesOp::prepare(&cwd)); + let ((), ticket) = (TabProxy::cd(&cwd), FilesOp::prepare(&cwd)); while let Some(chunk) = rx.next().await { FilesOp::Part(cwd.clone(), chunk, ticket).emit(); } @@ -90,7 +91,7 @@ impl Tab { if self.current.cwd.is_search() { let rep = self.history_new(&self.current.cwd.to_regular()); drop(mem::replace(&mut self.current, rep)); - Manager::_refresh(); + ManagerProxy::refresh(); } } } diff --git a/yazi-core/src/tab/commands/select.rs b/yazi-core/src/tab/commands/select.rs index 7f35c385..78fef324 100644 --- a/yazi-core/src/tab/commands/select.rs +++ b/yazi-core/src/tab/commands/select.rs @@ -1,8 +1,9 @@ use std::borrow::Cow; +use yazi_proxy::AppProxy; use yazi_shared::{event::Cmd, fs::Url, render, render_and}; -use crate::{notify::Notify, tab::Tab}; +use crate::tab::Tab; pub struct Opt<'a> { url: Option>, @@ -37,10 +38,7 @@ impl<'a> Tab { }; if !b { - Notify::_push_warn( - "Select one", - "This file cannot be selected, due to path nesting conflict.", - ); + AppProxy::warn("Select one", "This file cannot be selected, due to path nesting conflict."); } } } diff --git a/yazi-core/src/tab/commands/select_all.rs b/yazi-core/src/tab/commands/select_all.rs index 606d03ae..5182e42a 100644 --- a/yazi-core/src/tab/commands/select_all.rs +++ b/yazi-core/src/tab/commands/select_all.rs @@ -1,6 +1,7 @@ +use yazi_proxy::AppProxy; use yazi_shared::{event::Cmd, render}; -use crate::{notify::Notify, tab::Tab}; +use crate::tab::Tab; pub struct Opt { state: Option, @@ -35,10 +36,7 @@ impl Tab { render!(added > 0); if added != addition.len() { - Notify::_push_warn( - "Select all", - "Some files cannot be selected, due to path nesting conflict.", - ); + AppProxy::warn("Select all", "Some files cannot be selected, due to path nesting conflict."); } } } diff --git a/yazi-core/src/tab/commands/shell.rs b/yazi-core/src/tab/commands/shell.rs index 50545948..b05eab01 100644 --- a/yazi-core/src/tab/commands/shell.rs +++ b/yazi-core/src/tab/commands/shell.rs @@ -1,7 +1,8 @@ use yazi_config::{open::Opener, popup::InputCfg}; +use yazi_proxy::{InputProxy, TasksProxy}; use yazi_shared::event::Cmd; -use crate::{input::Input, tab::Tab, tasks::Tasks}; +use crate::tab::Tab; pub struct Opt { exec: String, @@ -30,14 +31,14 @@ impl Tab { tokio::spawn(async move { if !opt.confirm || opt.exec.is_empty() { - let mut result = Input::_show(InputCfg::shell(opt.block).with_value(opt.exec)); + let mut result = InputProxy::show(InputCfg::shell(opt.block).with_value(opt.exec)); match result.recv().await { Some(Ok(e)) => opt.exec = e, _ => return, } } - Tasks::_open_with(selected, Opener { + TasksProxy::open_with(selected, Opener { exec: opt.exec, block: opt.block, orphan: false, diff --git a/yazi-core/src/tab/commands/sort.rs b/yazi-core/src/tab/commands/sort.rs index bdf82d42..c36321db 100644 --- a/yazi-core/src/tab/commands/sort.rs +++ b/yazi-core/src/tab/commands/sort.rs @@ -1,9 +1,10 @@ use std::str::FromStr; use yazi_config::manager::SortBy; +use yazi_proxy::ManagerProxy; use yazi_shared::event::Cmd; -use crate::{manager::Manager, tab::Tab, tasks::Tasks}; +use crate::{tab::Tab, tasks::Tasks}; impl Tab { pub fn sort(&mut self, c: Cmd, tasks: &Tasks) { @@ -15,7 +16,7 @@ impl Tab { self.conf.sort_dir_first = c.named.contains_key("dir-first"); self.apply_files_attrs(); - Manager::_update_paged(); + ManagerProxy::update_paged(); tasks.preload_sorted(&self.current.files); } diff --git a/yazi-core/src/tasks/commands/inspect.rs b/yazi-core/src/tasks/commands/inspect.rs index d48ab454..d75bfcb2 100644 --- a/yazi-core/src/tasks/commands/inspect.rs +++ b/yazi-core/src/tasks/commands/inspect.rs @@ -2,7 +2,8 @@ use std::io::{stdout, Write}; use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use tokio::{io::{stdin, AsyncReadExt}, select, sync::mpsc, time}; -use yazi_scheduler::{Scheduler, BLOCKER}; +use yazi_proxy::AppProxy; +use yazi_scheduler::BLOCKER; use yazi_shared::{event::Cmd, term::Term, Defer}; use crate::tasks::Tasks; @@ -26,10 +27,10 @@ impl Tasks { task.logs.clone() }; - Scheduler::app_stop().await; + AppProxy::stop().await; let _defer = Defer::new(|| { disable_raw_mode().ok(); - Scheduler::app_resume(); + AppProxy::resume(); }); Term::clear(&mut stdout()).ok(); diff --git a/yazi-core/src/tasks/commands/open_with.rs b/yazi-core/src/tasks/commands/open_with.rs index bba96769..cbf247fd 100644 --- a/yazi-core/src/tasks/commands/open_with.rs +++ b/yazi-core/src/tasks/commands/open_with.rs @@ -1,25 +1,9 @@ -use yazi_config::open::Opener; -use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; +use yazi_proxy::OpenWithOpt; use crate::tasks::Tasks; -pub struct Opt { - targets: Vec, - opener: Opener, -} - -impl TryFrom for Opt { - type Error = (); - - fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } -} - impl Tasks { - pub fn _open_with(targets: Vec, opener: Opener) { - emit!(Call(Cmd::new("open_with").with_data(Opt { targets, opener }), Layer::Tasks)); - } - - pub fn open_with(&mut self, opt: impl TryInto) { + pub fn open_with(&mut self, opt: impl TryInto) { if let Ok(opt) = opt.try_into() { self.file_open_with(&opt.opener, &opt.targets); } diff --git a/yazi-fm/Cargo.toml b/yazi-fm/Cargo.toml index 30e4ac0e..e95d31df 100644 --- a/yazi-fm/Cargo.toml +++ b/yazi-fm/Cargo.toml @@ -14,6 +14,7 @@ yazi-boot = { path = "../yazi-boot", version = "0.2.3" } yazi-config = { path = "../yazi-config", version = "0.2.3" } yazi-core = { path = "../yazi-core", version = "0.2.3" } yazi-plugin = { path = "../yazi-plugin", version = "0.2.3" } +yazi-proxy = { path = "../yazi-proxy", version = "0.2.3" } yazi-scheduler = { path = "../yazi-scheduler", version = "0.2.3" } yazi-shared = { path = "../yazi-shared", version = "0.2.3" } diff --git a/yazi-fm/src/help/layout.rs b/yazi-fm/src/help/layout.rs index 1d78c169..633b3d67 100644 --- a/yazi-fm/src/help/layout.rs +++ b/yazi-fm/src/help/layout.rs @@ -19,7 +19,7 @@ impl<'a> Widget for Layout<'a> { let chunks = layout::Layout::vertical([Constraint::Fill(1), Constraint::Length(1)]).split(area); Line::styled( - help.keyword().unwrap_or_else(|| format!("{}.help", help.layer.to_string())), + help.keyword().unwrap_or_else(|| format!("{}.help", help.layer)), THEME.help.footer, ) .render(chunks[1], buf); diff --git a/yazi-fm/src/signals.rs b/yazi-fm/src/signals.rs index d7f93891..a1327e01 100644 --- a/yazi-fm/src/signals.rs +++ b/yazi-fm/src/signals.rs @@ -43,7 +43,8 @@ impl Signals { #[cfg(unix)] fn spawn_system_task(&self) -> Result> { use libc::{SIGCONT, SIGHUP, SIGINT, SIGQUIT, SIGTERM}; - use yazi_scheduler::{Scheduler, BLOCKER}; + use yazi_proxy::AppProxy; + use yazi_scheduler::BLOCKER; let mut signals = signal_hook_tokio::Signals::new([ // Terminating signals @@ -65,7 +66,7 @@ impl Signals { break; } } - SIGCONT => Scheduler::app_resume(), + SIGCONT => AppProxy::resume(), _ => {} } } diff --git a/yazi-plugin/Cargo.toml b/yazi-plugin/Cargo.toml index dd8d2fa6..3168c6cf 100644 --- a/yazi-plugin/Cargo.toml +++ b/yazi-plugin/Cargo.toml @@ -12,6 +12,7 @@ repository = "https://github.com/sxyazi/yazi" yazi-adaptor = { path = "../yazi-adaptor", version = "0.2.3" } yazi-boot = { path = "../yazi-boot", version = "0.2.3" } yazi-config = { path = "../yazi-config", version = "0.2.3" } +yazi-proxy = { path = "../yazi-proxy", version = "0.2.3" } yazi-shared = { path = "../yazi-shared", version = "0.2.3" } # External dependencies diff --git a/yazi-plugin/src/bindings/input.rs b/yazi-plugin/src/bindings/input.rs new file mode 100644 index 00000000..fd6b671c --- /dev/null +++ b/yazi-plugin/src/bindings/input.rs @@ -0,0 +1,32 @@ +use mlua::{prelude::LuaUserDataMethods, UserData}; +use tokio::sync::mpsc::UnboundedReceiver; +use yazi_shared::InputError; + +pub struct InputRx { + inner: UnboundedReceiver>, +} + +impl InputRx { + pub fn new(inner: UnboundedReceiver>) -> Self { Self { inner } } + + pub fn parse(res: Result) -> (Option, u8) { + match res { + Ok(s) => (Some(s), 1), + Err(InputError::Canceled(s)) => (Some(s), 2), + Err(InputError::Typed(s)) => (Some(s), 3), + _ => (None, 0), + } + } +} + +impl UserData for InputRx { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_async_method_mut("recv", |_, me, ()| async move { + let Some(res) = me.inner.recv().await else { + return Ok((None, 0)); + }; + + Ok(Self::parse(res)) + }); + } +} diff --git a/yazi-plugin/src/bindings/mod.rs b/yazi-plugin/src/bindings/mod.rs index cba217e6..57e87ef7 100644 --- a/yazi-plugin/src/bindings/mod.rs +++ b/yazi-plugin/src/bindings/mod.rs @@ -4,6 +4,8 @@ mod bindings; mod cha; mod file; mod icon; +mod input; +mod position; mod range; mod window; @@ -11,5 +13,7 @@ pub use bindings::*; pub use cha::*; pub use file::*; pub use icon::*; +pub use input::*; +pub use position::*; pub use range::*; pub use window::*; diff --git a/yazi-plugin/src/bindings/position.rs b/yazi-plugin/src/bindings/position.rs new file mode 100644 index 00000000..abe3206b --- /dev/null +++ b/yazi-plugin/src/bindings/position.rs @@ -0,0 +1,47 @@ +use std::{ops::Deref, str::FromStr}; + +use mlua::{ExternalResult, IntoLua}; + +pub struct Position(yazi_config::popup::Position); + +impl Deref for Position { + type Target = yazi_config::popup::Position; + + fn deref(&self) -> &Self::Target { &self.0 } +} + +impl From for yazi_config::popup::Position { + fn from(value: Position) -> Self { value.0 } +} + +impl<'a> TryFrom> for Position { + type Error = mlua::Error; + + fn try_from(t: mlua::Table<'a>) -> Result { + use yazi_config::popup::{Offset, Origin, Position}; + + Ok(Self(Position { + origin: Origin::from_str(t.raw_get::<_, mlua::String>(1)?.to_str()?).into_lua_err()?, + offset: Offset { + x: t.raw_get("x").unwrap_or_default(), + y: t.raw_get("y").unwrap_or_default(), + width: t.raw_get("w").unwrap_or_default(), + height: 3, + }, + })) + } +} + +impl<'lua> IntoLua<'lua> for Position { + fn into_lua(self, lua: &'lua mlua::Lua) -> mlua::Result { + lua + .create_table_from([ + (1.into_lua(lua)?, self.origin.to_string().into_lua(lua)?), + ("x".into_lua(lua)?, self.offset.x.into_lua(lua)?), + ("y".into_lua(lua)?, self.offset.y.into_lua(lua)?), + ("w".into_lua(lua)?, self.offset.width.into_lua(lua)?), + ("h".into_lua(lua)?, self.offset.height.into_lua(lua)?), + ])? + .into_lua(lua) + } +} diff --git a/yazi-plugin/src/utils/layer.rs b/yazi-plugin/src/utils/layer.rs index d71b54bc..50c28b53 100644 --- a/yazi-plugin/src/utils/layer.rs +++ b/yazi-plugin/src/utils/layer.rs @@ -1,11 +1,13 @@ use std::str::FromStr; -use mlua::{ExternalError, ExternalResult, Lua, Table, Value}; +use mlua::{ExternalError, ExternalResult, IntoLuaMulti, Lua, Table, Value}; use tokio::sync::mpsc; -use yazi_config::keymap::{Control, Key}; +use yazi_config::{keymap::{Control, Key}, popup::InputCfg}; +use yazi_proxy::InputProxy; use yazi_shared::{emit, event::Cmd, Layer}; use super::Utils; +use crate::bindings::{InputRx, Position}; impl Utils { fn parse_keys(value: Value) -> mlua::Result> { @@ -53,6 +55,30 @@ impl Utils { })?, )?; + ya.raw_set( + "input", + lua.create_async_function(|lua, t: Table| async move { + let realtime = t.raw_get("realtime").unwrap_or_default(); + let mut rx = InputProxy::show(InputCfg { + title: t.raw_get("title")?, + value: t.raw_get("value").unwrap_or_default(), + cursor: None, // TODO + position: Position::try_from(t.raw_get::<_, Table>("position")?)?.into(), + realtime, + completion: false, + highlight: false, + }); + + if realtime { + (InputRx::new(rx), Value::Nil).into_lua_multi(lua) + } else if let Some(res) = rx.recv().await { + InputRx::parse(res).into_lua_multi(lua) + } else { + (Value::Nil, 0).into_lua_multi(lua) + } + })?, + )?; + Ok(()) } } diff --git a/yazi-proxy/Cargo.toml b/yazi-proxy/Cargo.toml new file mode 100644 index 00000000..fa1211ca --- /dev/null +++ b/yazi-proxy/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "yazi-proxy" +version = "0.2.3" +edition = "2021" +license = "MIT" +authors = [ "sxyazi " ] +description = "Yazi event proxy" +homepage = "https://yazi-rs.github.io" +repository = "https://github.com/sxyazi/yazi" + +[dependencies] +yazi-config = { path = "../yazi-config", version = "0.2.3" } +yazi-shared = { path = "../yazi-shared", version = "0.2.3" } + +# External dependencies +anyhow = "^1" +tokio = { version = "^1", features = [ "parking_lot" ] } diff --git a/yazi-proxy/src/app.rs b/yazi-proxy/src/app.rs new file mode 100644 index 00000000..dd5ac3d7 --- /dev/null +++ b/yazi-proxy/src/app.rs @@ -0,0 +1,30 @@ +use tokio::sync::oneshot; +use yazi_shared::{emit, event::Cmd, Layer}; + +pub struct AppProxy; + +impl AppProxy { + #[inline] + pub async fn stop() { + let (tx, rx) = oneshot::channel::<()>(); + emit!(Call(Cmd::new("stop").with_data(tx), Layer::App)); + rx.await.ok(); + } + + #[inline] + pub fn resume() { + emit!(Call(Cmd::new("resume"), Layer::App)); + } + + #[inline] + pub fn warn(title: &str, content: &str) { + emit!(Call( + Cmd::new("notify") + .with("title", title) + .with("content", content) + .with("level", "warn") + .with("timeout", 5), + Layer::App + )); + } +} diff --git a/yazi-proxy/src/completion.rs b/yazi-proxy/src/completion.rs new file mode 100644 index 00000000..583c4b75 --- /dev/null +++ b/yazi-proxy/src/completion.rs @@ -0,0 +1,18 @@ +use yazi_shared::{emit, event::Cmd, Layer}; + +pub struct CompletionProxy; + +impl CompletionProxy { + #[inline] + pub fn close() { + emit!(Call(Cmd::new("close"), Layer::Completion)); + } + + #[inline] + pub fn trigger(word: &str, ticket: usize) { + emit!(Call( + Cmd::args("trigger", vec![word.to_owned()]).with("ticket", ticket), + Layer::Completion + )); + } +} diff --git a/yazi-proxy/src/input.rs b/yazi-proxy/src/input.rs new file mode 100644 index 00000000..5a92b452 --- /dev/null +++ b/yazi-proxy/src/input.rs @@ -0,0 +1,30 @@ +use tokio::sync::mpsc; +use yazi_config::popup::InputCfg; +use yazi_shared::{emit, event::Cmd, InputError, Layer}; + +pub struct InputOpt { + pub cfg: InputCfg, + pub tx: mpsc::UnboundedSender>, +} + +impl TryFrom for InputOpt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } +} + +pub struct InputProxy; + +impl InputProxy { + #[inline] + pub fn show(cfg: InputCfg) -> mpsc::UnboundedReceiver> { + let (tx, rx) = mpsc::unbounded_channel(); + emit!(Call(Cmd::new("show").with_data(InputOpt { cfg, tx }), Layer::Input)); + rx + } + + #[inline] + pub fn complete(word: &str, ticket: usize) { + emit!(Call(Cmd::args("complete", vec![word.to_owned()]).with("ticket", ticket), Layer::Input)); + } +} diff --git a/yazi-proxy/src/lib.rs b/yazi-proxy/src/lib.rs new file mode 100644 index 00000000..79993c29 --- /dev/null +++ b/yazi-proxy/src/lib.rs @@ -0,0 +1,15 @@ +mod app; +mod completion; +mod input; +mod manager; +mod select; +mod tab; +mod tasks; + +pub use app::*; +pub use completion::*; +pub use input::*; +pub use manager::*; +pub use select::*; +pub use tab::*; +pub use tasks::*; diff --git a/yazi-proxy/src/manager.rs b/yazi-proxy/src/manager.rs new file mode 100644 index 00000000..8aa0f561 --- /dev/null +++ b/yazi-proxy/src/manager.rs @@ -0,0 +1,60 @@ +use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; + +#[derive(Default)] +pub struct OpenDoOpt { + pub hovered: Url, + pub targets: Vec<(Url, String)>, + pub interactive: bool, +} + +impl From for OpenDoOpt { + fn from(mut c: Cmd) -> Self { c.take_data().unwrap_or_default() } +} + +pub struct ManagerProxy; + +impl ManagerProxy { + #[inline] + pub fn peek(force: bool) { + emit!(Call(Cmd::new("peek").with_bool("force", force), Layer::Manager)); + } + + #[inline] + pub fn hover(url: Option) { + emit!(Call( + Cmd::args("hover", url.map_or_else(Vec::new, |u| vec![u.to_string()])), + Layer::Manager + )); + } + + #[inline] + pub fn refresh() { + emit!(Call(Cmd::new("refresh"), Layer::Manager)); + } + + #[inline] + pub fn open_do(opt: OpenDoOpt) { + emit!(Call(Cmd::new("open_do").with_data(opt), Layer::Manager)); + } + + #[inline] + pub fn remove_do(targets: Vec, permanently: bool) { + emit!(Call( + Cmd::new("remove_do").with_bool("permanently", permanently).with_data(targets), + Layer::Manager + )); + } + + #[inline] + pub fn update_paged() { + emit!(Call(Cmd::new("update_paged"), Layer::Manager)); + } + + #[inline] + pub fn update_paged_by(page: usize, only_if: &Url) { + emit!(Call( + Cmd::args("update_paged", vec![page.to_string()]).with("only-if", only_if.to_string()), + Layer::Manager + )); + } +} diff --git a/yazi-proxy/src/select.rs b/yazi-proxy/src/select.rs new file mode 100644 index 00000000..518176dd --- /dev/null +++ b/yazi-proxy/src/select.rs @@ -0,0 +1,25 @@ +use tokio::sync::oneshot; +use yazi_config::popup::SelectCfg; +use yazi_shared::{emit, event::Cmd, term::Term, Layer}; + +pub struct SelectOpt { + pub cfg: SelectCfg, + pub tx: oneshot::Sender>, +} + +impl TryFrom for SelectOpt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } +} + +pub struct SelectProxy; + +impl SelectProxy { + #[inline] + pub async fn show(cfg: SelectCfg) -> anyhow::Result { + let (tx, rx) = oneshot::channel(); + emit!(Call(Cmd::new("show").with_data(SelectOpt { cfg, tx }), Layer::Select)); + rx.await.unwrap_or_else(|_| Term::goodbye(|| false)) + } +} diff --git a/yazi-proxy/src/tab.rs b/yazi-proxy/src/tab.rs new file mode 100644 index 00000000..4f01e821 --- /dev/null +++ b/yazi-proxy/src/tab.rs @@ -0,0 +1,15 @@ +use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; + +pub struct TabProxy; + +impl TabProxy { + #[inline] + pub fn cd(target: &Url) { + emit!(Call(Cmd::args("cd", vec![target.to_string()]), Layer::Manager)); + } + + #[inline] + pub fn reveal(target: &Url) { + emit!(Call(Cmd::args("reveal", vec![target.to_string()]), Layer::Manager)); + } +} diff --git a/yazi-proxy/src/tasks.rs b/yazi-proxy/src/tasks.rs new file mode 100644 index 00000000..d60672fc --- /dev/null +++ b/yazi-proxy/src/tasks.rs @@ -0,0 +1,22 @@ +use yazi_config::open::Opener; +use yazi_shared::{emit, event::Cmd, fs::Url, Layer}; + +pub struct TasksProxy; + +pub struct OpenWithOpt { + pub targets: Vec, + pub opener: Opener, +} + +impl TryFrom for OpenWithOpt { + type Error = (); + + fn try_from(mut c: Cmd) -> Result { c.take_data().ok_or(()) } +} + +impl TasksProxy { + #[inline] + pub fn open_with(targets: Vec, opener: Opener) { + emit!(Call(Cmd::new("open_with").with_data(OpenWithOpt { targets, opener }), Layer::Tasks)); + } +} diff --git a/yazi-scheduler/Cargo.toml b/yazi-scheduler/Cargo.toml index 104ff99c..e6488457 100644 --- a/yazi-scheduler/Cargo.toml +++ b/yazi-scheduler/Cargo.toml @@ -11,8 +11,9 @@ repository = "https://github.com/sxyazi/yazi" [dependencies] yazi-adaptor = { path = "../yazi-adaptor", version = "0.2.3" } yazi-config = { path = "../yazi-config", version = "0.2.3" } -yazi-shared = { path = "../yazi-shared", version = "0.2.3" } yazi-plugin = { path = "../yazi-plugin", version = "0.2.3" } +yazi-proxy = { path = "../yazi-proxy", version = "0.2.3" } +yazi-shared = { path = "../yazi-shared", version = "0.2.3" } # External dependencies anyhow = "^1" diff --git a/yazi-scheduler/src/process/process.rs b/yazi-scheduler/src/process/process.rs index 2431db80..12582964 100644 --- a/yazi-scheduler/src/process/process.rs +++ b/yazi-scheduler/src/process/process.rs @@ -1,9 +1,10 @@ use anyhow::Result; use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::mpsc}; use yazi_plugin::external::{self, ShellOpt}; +use yazi_proxy::AppProxy; use super::ProcessOpOpen; -use crate::{Scheduler, TaskProg, BLOCKER}; +use crate::{TaskProg, BLOCKER}; pub struct Process { prog: mpsc::UnboundedSender, @@ -16,7 +17,7 @@ impl Process { let opt = ShellOpt::from(&mut task); if task.block { let _guard = BLOCKER.acquire().await.unwrap(); - Scheduler::app_stop().await; + AppProxy::stop().await; match external::shell(opt) { Ok(mut child) => { @@ -28,7 +29,7 @@ impl Process { self.fail(task.id, format!("Failed to spawn process: {e}"))?; } } - return Ok(Scheduler::app_resume()); + return Ok(AppProxy::resume()); } if task.orphan { diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index fc6dbf4c..9870b2ea 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -5,7 +5,7 @@ use parking_lot::Mutex; use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}}; use yazi_config::{open::Opener, plugin::PluginRule, TASKS}; use yazi_plugin::ValueSendable; -use yazi_shared::{emit, event::Cmd, fs::{unique_path, Url}, Layer, Throttle}; +use yazi_shared::{fs::{unique_path, Url}, Throttle}; use super::{Running, TaskProg, TaskStage}; use crate::{file::{File, FileOpDelete, FileOpLink, FileOpPaste, FileOpTrash}, plugin::{Plugin, PluginOpEntry}, preload::{Preload, PreloadOpRule, PreloadOpSize}, process::{Process, ProcessOpOpen}, TaskKind, TaskOp, HIGH, LOW, NORMAL}; @@ -163,16 +163,6 @@ impl Scheduler { b } - pub async fn app_stop() { - let (tx, rx) = oneshot::channel::<()>(); - emit!(Call(Cmd::new("stop").with_data(tx), Layer::App)); - rx.await.ok(); - } - - pub fn app_resume() { - emit!(Call(Cmd::new("resume"), Layer::App)); - } - pub fn file_cut(&self, from: Url, mut to: Url, force: bool) { let mut running = self.running.lock(); let id = running.add(TaskKind::User, format!("Cut {:?} to {:?}", from, to));