This commit is contained in:
sxyazi 2024-03-02 16:07:44 +08:00
parent b71bd8a30e
commit 9e05099a50
No known key found for this signature in database
48 changed files with 333 additions and 263 deletions

1
Cargo.lock generated
View file

@ -2816,6 +2816,7 @@ checksum = "f4b6c8e12e39ac0f79fa96f36e5b88e0da8d230691abd729eec709b43c74f632"
name = "yazi-proxy" name = "yazi-proxy"
version = "0.2.3" version = "0.2.3"
dependencies = [ dependencies = [
"anyhow",
"tokio", "tokio",
"yazi-config", "yazi-config",
"yazi-shared", "yazi-shared",

View file

@ -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 { pub struct Opt {
submit: bool, submit: bool,
@ -11,16 +12,11 @@ impl From<Cmd> for Opt {
} }
impl Completion { impl Completion {
#[inline]
pub fn _close() {
emit!(Call(Cmd::new("close"), Layer::Completion));
}
pub fn close(&mut self, opt: impl Into<Opt>) { pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if let Some(s) = self.selected().filter(|_| opt.submit) { if let Some(s) = self.selected().filter(|_| opt.submit) {
Input::_complete(s, self.ticket); InputProxy::complete(s, self.ticket);
} }
self.caches.clear(); self.caches.clear();

View file

@ -20,14 +20,6 @@ impl From<Cmd> for Opt {
} }
impl Completion { 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<Opt>) { pub fn trigger(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if opt.ticket < self.ticket { if opt.ticket < self.ticket {

View file

@ -2,10 +2,11 @@ use std::{mem, time::SystemTime};
use ratatui::layout::Rect; use ratatui::layout::Rect;
use yazi_config::{LAYOUT, MANAGER}; use yazi_config::{LAYOUT, MANAGER};
use yazi_proxy::ManagerProxy;
use yazi_shared::fs::{File, FilesOp, Url}; use yazi_shared::fs::{File, FilesOp, Url};
use super::FolderStage; use super::FolderStage;
use crate::{folder::Files, manager::Manager, Step}; use crate::{folder::Files, Step};
#[derive(Default)] #[derive(Default)]
pub struct Folder { pub struct Folder {
@ -99,7 +100,7 @@ impl Folder {
let new = self.cursor / limit; let new = self.cursor / limit;
if mem::replace(&mut self.page, new) != new || force { if mem::replace(&mut self.page, new) != new || force {
Manager::_update_paged_by(new, &self.cwd); ManagerProxy::update_paged_by(new, &self.cwd);
} }
} }

View file

@ -1,6 +1,7 @@
use yazi_proxy::CompletionProxy;
use yazi_shared::{event::Cmd, render, InputError}; use yazi_shared::{event::Cmd, render, InputError};
use crate::{completion::Completion, input::Input}; use crate::input::Input;
pub struct Opt { pub struct Opt {
submit: bool, submit: bool,
@ -18,7 +19,7 @@ impl Input {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if self.completion { if self.completion {
Completion::_close(); CompletionProxy::close();
} }
if let Some(cb) = self.callback.take() { if let Some(cb) = self.callback.take() {

View file

@ -1,6 +1,6 @@
use std::path::MAIN_SEPARATOR; use std::path::MAIN_SEPARATOR;
use yazi_shared::{emit, event::Cmd, render, Layer}; use yazi_shared::{event::Cmd, render};
use crate::input::Input; use crate::input::Input;
@ -19,11 +19,6 @@ impl From<Cmd> for Opt {
} }
impl Input { 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<Opt>) { pub fn complete(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
if self.ticket != opt.ticket { if self.ticket != opt.ticket {

View file

@ -1,6 +1,7 @@
use yazi_proxy::CompletionProxy;
use yazi_shared::{event::Cmd, render}; 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; pub struct Opt;
@ -26,7 +27,7 @@ impl Input {
self.move_(-1); self.move_(-1);
if self.completion { if self.completion {
Completion::_close(); CompletionProxy::close();
} }
} }
} }

View file

@ -1,28 +1,10 @@
use tokio::sync::mpsc; use yazi_proxy::InputOpt;
use yazi_config::popup::InputCfg; use yazi_shared::render;
use yazi_shared::{emit, event::Cmd, render, InputError, Layer};
use crate::input::Input; use crate::input::Input;
pub struct Opt {
cfg: InputCfg,
tx: mpsc::UnboundedSender<Result<String, InputError>>,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
}
impl Input { impl Input {
pub fn _show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> { pub fn show(&mut self, opt: impl TryInto<InputOpt>) {
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<Opt>) {
let Ok(opt) = opt.try_into() else { let Ok(opt) = opt.try_into() else {
return; return;
}; };

View file

@ -2,9 +2,10 @@ use std::path::PathBuf;
use tokio::fs; use tokio::fs;
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_proxy::{InputProxy, ManagerProxy};
use yazi_shared::{event::Cmd, fs::{File, FilesOp, Url}}; use yazi_shared::{event::Cmd, fs::{File, FilesOp, Url}};
use crate::{input::Input, manager::Manager}; use crate::manager::Manager;
pub struct Opt { pub struct Opt {
force: bool, force: bool,
@ -19,14 +20,14 @@ impl Manager {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
let cwd = self.cwd().to_owned(); let cwd = self.cwd().to_owned();
tokio::spawn(async move { 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 { let Some(Ok(name)) = result.recv().await else {
return Ok(()); return Ok(());
}; };
let path = cwd.join(&name); let path = cwd.join(&name);
if !opt.force && fs::symlink_metadata(&path).await.is_ok() { 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" => (), Some(Ok(c)) if c == "y" || c == "Y" => (),
_ => return Ok(()), _ => return Ok(()),
} }
@ -43,7 +44,7 @@ impl Manager {
Url::from(path.components().take(cwd.components().count() + 1).collect::<PathBuf>()); Url::from(path.components().take(cwd.components().count() + 1).collect::<PathBuf>());
if let Ok(f) = File::from(child.clone()).await { if let Ok(f) = File::from(child.clone()).await {
FilesOp::Creating(cwd, vec![f]).emit(); FilesOp::Creating(cwd, vec![f]).emit();
Manager::_hover(Some(child)); ManagerProxy::hover(Some(child));
} }
Ok::<(), anyhow::Error>(()) Ok::<(), anyhow::Error>(())
}); });

View file

@ -1,6 +1,6 @@
use std::collections::BTreeSet; 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; use crate::manager::Manager;
@ -16,14 +16,6 @@ impl From<Option<Url>> for Opt {
} }
impl Manager { impl Manager {
#[inline]
pub fn _hover(url: Option<Url>) {
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<Opt>) { pub fn hover(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;

View file

@ -4,9 +4,10 @@ use tracing::error;
use yazi_boot::ARGS; use yazi_boot::ARGS;
use yazi_config::{popup::SelectCfg, OPEN}; use yazi_config::{popup::SelectCfg, OPEN};
use yazi_plugin::isolate; 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 { pub struct Opt {
interactive: bool, interactive: bool,
@ -22,17 +23,6 @@ impl From<Cmd> for Opt {
} }
} }
#[derive(Default)]
pub struct OptDo {
hovered: Url,
targets: Vec<(Url, String)>,
interactive: bool,
}
impl From<Cmd> for OptDo {
fn from(mut c: Cmd) -> Self { c.take_data().unwrap_or_default() }
}
impl Manager { impl Manager {
pub fn open(&mut self, opt: impl Into<Opt>, tasks: &Tasks) { pub fn open(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
if !self.active_mut().try_escape_visual() { if !self.active_mut().try_escape_visual() {
@ -60,7 +50,8 @@ impl Manager {
} }
if todo.is_empty() { 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 { tokio::spawn(async move {
@ -76,17 +67,12 @@ impl Manager {
error!("preload in open failed: {e}"); 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(&mut self, opt: impl Into<OpenDoOpt>, tasks: &Tasks) {
pub fn _open_do(opt: OptDo) { let opt = opt.into() as OpenDoOpt;
emit!(Call(Cmd::new("open_do").with_data(opt), Layer::Manager));
}
pub fn open_do(&mut self, opt: impl Into<OptDo>, tasks: &Tasks) {
let opt = opt.into() as OptDo;
let targets: Vec<_> = opt let targets: Vec<_> = opt
.targets .targets
.into_iter() .into_iter()
@ -108,9 +94,11 @@ impl Manager {
let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect(); let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect();
tokio::spawn(async move { 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 { if let Ok(choice) = result.await {
Tasks::_open_with(urls, openers[choice].clone()); TasksProxy::open_with(urls, openers[choice].clone());
} }
}); });
} }

View file

@ -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; use crate::manager::Manager;
@ -25,11 +25,6 @@ impl From<bool> for Opt {
} }
impl Manager { 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<Opt>) { pub fn peek(&mut self, opt: impl Into<Opt>) {
let Some(hovered) = self.hovered().cloned() else { let Some(hovered) = self.hovered().cloned() else {
return render!(self.active_mut().preview.reset()); return render!(self.active_mut().preview.reset());

View file

@ -1,7 +1,8 @@
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_proxy::InputProxy;
use yazi_shared::{emit, event::{Cmd, EventQuit}}; use yazi_shared::{emit, event::{Cmd, EventQuit}};
use crate::{input::Input, manager::Manager, tasks::Tasks}; use crate::{manager::Manager, tasks::Tasks};
#[derive(Default)] #[derive(Default)]
pub struct Opt { pub struct Opt {
@ -25,7 +26,7 @@ impl Manager {
} }
tokio::spawn(async move { 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 let Some(Ok(choice)) = result.recv().await {
if choice == "y" || choice == "Y" { if choice == "y" || choice == "Y" {
emit!(Quit(opt)); emit!(Quit(opt));

View file

@ -1,15 +1,10 @@
use std::env; use std::env;
use yazi_shared::{emit, event::Cmd, Layer}; use yazi_shared::event::Cmd;
use crate::{manager::Manager, tasks::Tasks}; use crate::{manager::Manager, tasks::Tasks};
impl Manager { impl Manager {
#[inline]
pub fn _refresh() {
emit!(Call(Cmd::new("refresh"), Layer::Manager));
}
pub fn refresh(&mut self, _: Cmd, tasks: &Tasks) { pub fn refresh(&mut self, _: Cmd, tasks: &Tasks) {
env::set_current_dir(self.cwd()).ok(); env::set_current_dir(self.cwd()).ok();
env::set_var("PWD", self.cwd()); env::set_var("PWD", self.cwd());

View file

@ -1,7 +1,8 @@
use yazi_config::popup::InputCfg; 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 { pub struct Opt {
force: bool, force: bool,
@ -33,7 +34,7 @@ impl Manager {
} }
tokio::spawn(async move { 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()) InputCfg::delete(opt.targets.len())
} else { } else {
InputCfg::trash(opt.targets.len()) InputCfg::trash(opt.targets.len())
@ -44,19 +45,11 @@ impl Manager {
return; return;
} }
Self::_remove_do(opt.targets, opt.permanently); ManagerProxy::remove_do(opt.targets, opt.permanently);
} }
}); });
} }
#[inline]
pub fn _remove_do(targets: Vec<Url>, 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<Opt>, tasks: &Tasks) { pub fn remove_do(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
for u in &opt.targets { for u in &opt.targets {

View file

@ -4,11 +4,11 @@ use anyhow::{anyhow, bail, Result};
use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}}; use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
use yazi_config::{popup::InputCfg, OPEN, PREVIEW}; use yazi_config::{popup::InputCfg, OPEN, PREVIEW};
use yazi_plugin::external::{self, ShellOpt}; use yazi_plugin::external::{self, ShellOpt};
use yazi_proxy::App; use yazi_proxy::{AppProxy, InputProxy, ManagerProxy};
use yazi_scheduler::BLOCKER; use yazi_scheduler::BLOCKER;
use yazi_shared::{event::Cmd, fs::{max_common_root, File, FilesOp, Url}, term::Term, Defer}; 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 { pub struct Opt {
force: bool, force: bool,
@ -50,7 +50,7 @@ impl Manager {
let file = File::from(new.clone()).await?; let file = File::from(new.clone()).await?;
FilesOp::Deleting(file.parent().unwrap(), vec![new.clone()]).emit(); FilesOp::Deleting(file.parent().unwrap(), vec![new.clone()]).emit();
FilesOp::Upserting(file.parent().unwrap(), BTreeMap::from_iter([(old, file)])).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<Opt>) { pub fn rename(&mut self, opt: impl Into<Opt>) {
@ -78,7 +78,7 @@ impl Manager {
}; };
tokio::spawn(async move { 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 { let Some(Ok(name)) = result.recv().await else {
return; return;
}; };
@ -89,7 +89,7 @@ impl Manager {
return; return;
} }
let mut result = Input::_show(InputCfg::overwrite()); let mut result = InputProxy::show(InputCfg::overwrite());
if let Some(Ok(choice)) = result.recv().await { if let Some(Ok(choice)) = result.recv().await {
if choice == "y" || choice == "Y" { if choice == "y" || choice == "Y" {
Self::rename_and_hover(hovered, Url::from(new)).await.ok(); Self::rename_and_hover(hovered, Url::from(new)).await.ok();
@ -123,10 +123,10 @@ impl Manager {
let _guard = BLOCKER.acquire().await.unwrap(); let _guard = BLOCKER.acquire().await.unwrap();
let _defer = Defer::new(|| { let _defer = Defer::new(|| {
App::resume(); AppProxy::resume();
tokio::spawn(fs::remove_file(tmp.clone())) tokio::spawn(fs::remove_file(tmp.clone()))
}); });
App::stop().await; AppProxy::stop().await;
let mut child = external::shell(ShellOpt { let mut child = external::shell(ShellOpt {
cmd: (*opener.exec).into(), cmd: (*opener.exec).into(),

View file

@ -1,4 +1,4 @@
use yazi_proxy::App; use yazi_proxy::AppProxy;
use yazi_shared::event::Cmd; use yazi_shared::event::Cmd;
use crate::manager::Manager; use crate::manager::Manager;
@ -7,7 +7,7 @@ impl Manager {
pub fn suspend(&mut self, _: Cmd) { pub fn suspend(&mut self, _: Cmd) {
#[cfg(unix)] #[cfg(unix)]
tokio::spawn(async move { tokio::spawn(async move {
App::stop().await; AppProxy::stop().await;
unsafe { libc::raise(libc::SIGTSTP) }; unsafe { libc::raise(libc::SIGTSTP) };
}); });
} }

View file

@ -1,5 +1,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use yazi_proxy::ManagerProxy;
use yazi_shared::{event::Cmd, fs::FilesOp, render}; use yazi_shared::{event::Cmd, fs::FilesOp, render};
use crate::{folder::Folder, manager::Manager, tab::Tab, tasks::Tasks}; use crate::{folder::Folder, manager::Manager, tab::Tab, tasks::Tasks};
@ -56,8 +57,8 @@ impl Manager {
return; return;
} }
Self::_hover(None); // Re-hover in next loop ManagerProxy::hover(None); // Re-hover in next loop
Self::_update_paged(); // Update for paged files in next loop ManagerProxy::update_paged(); // Update for paged files in next loop
if calc { if calc {
tasks.preload_sorted(&tab.current.files); tasks.preload_sorted(&tab.current.files);
} }
@ -73,7 +74,7 @@ impl Manager {
} }
if !foreign { if !foreign {
Self::_peek(true); ManagerProxy::peek(true);
} }
} }

View file

@ -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}; use crate::{manager::Manager, tasks::Tasks};
@ -22,19 +22,6 @@ impl From<()> for Opt {
} }
impl Manager { 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<Opt>, tasks: &Tasks) { pub fn update_paged(&mut self, opt: impl TryInto<Opt>, tasks: &Tasks) {
let Ok(opt) = opt.try_into() else { let Ok(opt) = opt.try_into() else {
return; return;

View file

@ -1,9 +1,10 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use yazi_boot::BOOT; use yazi_boot::BOOT;
use yazi_proxy::ManagerProxy;
use yazi_shared::fs::Url; use yazi_shared::fs::Url;
use crate::{manager::Manager, tab::Tab}; use crate::tab::Tab;
pub struct Tabs { pub struct Tabs {
pub idx: usize, pub idx: usize,
@ -17,7 +18,7 @@ impl Tabs {
tabs.items[0].reveal(Url::from(BOOT.cwd.join(file))); tabs.items[0].reveal(Url::from(BOOT.cwd.join(file)));
} }
Manager::_refresh(); ManagerProxy::refresh();
tabs tabs
} }
@ -42,8 +43,8 @@ impl Tabs {
} }
self.idx = idx; self.idx = idx;
Manager::_refresh(); ManagerProxy::refresh();
Manager::_peek(true); ManagerProxy::peek(true);
} }
} }

View file

@ -5,18 +5,6 @@ use yazi_shared::{emit, event::Cmd, Layer};
use crate::notify::{Message, Notify}; use crate::notify::{Message, Notify};
impl 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<Message>) { pub fn push(&mut self, msg: impl TryInto<Message>) {
let Ok(mut msg) = msg.try_into() else { let Ok(mut msg) = msg.try_into() else {
return; return;

View file

@ -1,29 +1,10 @@
use anyhow::Result; use yazi_proxy::SelectOpt;
use tokio::sync::oneshot; use yazi_shared::render;
use yazi_config::popup::SelectCfg;
use yazi_shared::{emit, event::Cmd, render, term::Term, Layer};
use crate::select::Select; use crate::select::Select;
pub struct Opt {
cfg: SelectCfg,
tx: oneshot::Sender<Result<usize>>,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
}
impl Select { impl Select {
pub async fn _show(cfg: SelectCfg) -> Result<usize> { pub fn show(&mut self, opt: impl TryInto<SelectOpt>) {
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<Opt>) {
let Ok(opt) = opt.try_into() else { let Ok(opt) = opt.try_into() else {
return; return;
}; };

View file

@ -1,6 +1,7 @@
use yazi_proxy::ManagerProxy;
use yazi_shared::{event::Cmd, render}; use yazi_shared::{event::Cmd, render};
use crate::{manager::Manager, tab::Tab, Step}; use crate::{tab::Tab, Step};
pub struct Opt { pub struct Opt {
step: Step, step: Step,
@ -36,7 +37,7 @@ impl Tab {
} }
} }
Manager::_hover(None); ManagerProxy::hover(None);
render!(); render!();
} }
} }

View file

@ -3,9 +3,10 @@ use std::{mem, time::Duration};
use tokio::{fs, pin}; use tokio::{fs, pin};
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::popup::InputCfg; 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 { pub struct Opt {
target: Url, target: Url,
@ -27,11 +28,6 @@ impl From<Url> for Opt {
} }
impl Tab { 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<Opt>) { pub fn cd(&mut self, opt: impl Into<Opt>) {
if !self.try_escape_visual() { if !self.try_escape_visual() {
return; return;
@ -68,13 +64,13 @@ impl Tab {
self.backstack.push(opt.target.clone()); self.backstack.push(opt.target.clone());
} }
Manager::_refresh(); ManagerProxy::refresh();
render!(); render!();
} }
fn cd_interactive(&mut self) { fn cd_interactive(&mut self) {
tokio::spawn(async move { 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)); let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
pin!(rx); pin!(rx);
@ -88,13 +84,13 @@ impl Tab {
}; };
if meta.is_dir() { if meta.is_dir() {
Tab::_cd(&u); TabProxy::cd(&u);
} else { } else {
Tab::_reveal(&u); TabProxy::reveal(&u);
} }
} }
Err(InputError::Completed(before, ticket)) => { Err(InputError::Completed(before, ticket)) => {
Completion::_trigger(&before, ticket); CompletionProxy::trigger(&before, ticket);
} }
_ => break, _ => break,
} }

View file

@ -1,7 +1,8 @@
use bitflags::bitflags; use bitflags::bitflags;
use yazi_proxy::{AppProxy, ManagerProxy};
use yazi_shared::{event::Cmd, render, render_and}; use yazi_shared::{event::Cmd, render, render_and};
use crate::{manager::Manager, notify::Notify, tab::Tab}; use crate::tab::Tab;
bitflags! { bitflags! {
pub struct Opt: u8 { pub struct Opt: u8 {
@ -74,7 +75,7 @@ impl Tab {
self.selected.clear(); self.selected.clear();
if self.current.hovered().is_some_and(|h| h.is_dir()) { if self.current.hovered().is_some_and(|h| h.is_dir()) {
Manager::_peek(true); ManagerProxy::peek(true);
} }
render_and!(true) render_and!(true)
} }
@ -110,7 +111,7 @@ impl Tab {
if !select { if !select {
self.selected.remove_many(&urls); self.selected.remove_many(&urls);
} else if self.selected.add_many(&urls) != urls.len() { } else if self.selected.add_many(&urls) != urls.len() {
Notify::_push_warn( AppProxy::warn(
"Escape visual mode", "Escape visual mode",
"Some files cannot be selected, due to path nesting conflict.", "Some files cannot be selected, due to path nesting conflict.",
); );

View file

@ -3,9 +3,10 @@ use std::time::Duration;
use tokio::pin; use tokio::pin;
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_proxy::{InputProxy, ManagerProxy};
use yazi_shared::{emit, event::Cmd, render, Debounce, InputError, Layer}; 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)] #[derive(Default)]
pub struct Opt { pub struct Opt {
@ -28,7 +29,7 @@ impl Tab {
pub fn filter(&mut self, opt: impl Into<Opt>) { pub fn filter(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
tokio::spawn(async move { 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)); let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
pin!(rx); pin!(rx);
@ -62,7 +63,7 @@ impl Tab {
}; };
if opt.done { 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()); let hovered = self.current.hovered().map(|f| f.url());
@ -71,7 +72,7 @@ impl Tab {
} }
if self.current.repos(hovered) { if self.current.repos(hovered) {
Manager::_hover(None); ManagerProxy::hover(None);
} }
render!(); render!();
} }

View file

@ -3,9 +3,10 @@ use std::time::Duration;
use tokio::pin; use tokio::pin;
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_proxy::InputProxy;
use yazi_shared::{emit, event::Cmd, render, Debounce, InputError, Layer}; 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 { pub struct Opt {
query: Option<String>, query: Option<String>,
@ -35,7 +36,7 @@ impl Tab {
pub fn find(&mut self, opt: impl Into<Opt>) { pub fn find(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
tokio::spawn(async move { 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)); let rx = Debounce::new(UnboundedReceiverStream::new(rx), Duration::from_millis(50));
pin!(rx); pin!(rx);

View file

@ -1,6 +1,7 @@
use yazi_proxy::ManagerProxy;
use yazi_shared::event::Cmd; use yazi_shared::event::Cmd;
use crate::{manager::Manager, tab::Tab}; use crate::tab::Tab;
impl Tab { impl Tab {
pub fn hidden(&mut self, c: Cmd) { pub fn hidden(&mut self, c: Cmd) {
@ -14,10 +15,10 @@ impl Tab {
self.apply_files_attrs(); self.apply_files_attrs();
if hovered.as_ref() != self.current.hovered().map(|f| &f.url) { 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()) { } else if self.current.hovered().is_some_and(|f| f.is_dir()) {
Manager::_peek(true); ManagerProxy::peek(true);
} }
Manager::_update_paged(); ManagerProxy::update_paged();
} }
} }

View file

@ -1,5 +1,5 @@
use yazi_plugin::external::{self, FzfOpt, ZoxideOpt}; use yazi_plugin::external::{self, FzfOpt, ZoxideOpt};
use yazi_proxy::App; use yazi_proxy::{AppProxy, TabProxy};
use yazi_scheduler::BLOCKER; use yazi_scheduler::BLOCKER;
use yazi_shared::{event::Cmd, fs::ends_with_slash, Defer}; use yazi_shared::{event::Cmd, fs::ends_with_slash, Defer};
@ -38,8 +38,8 @@ impl Tab {
let cwd = self.current.cwd.clone(); let cwd = self.current.cwd.clone();
tokio::spawn(async move { tokio::spawn(async move {
let _guard = BLOCKER.acquire().await.unwrap(); let _guard = BLOCKER.acquire().await.unwrap();
let _defer = Defer::new(App::resume); let _defer = Defer::new(AppProxy::resume);
App::stop().await; AppProxy::stop().await;
let result = if opt.type_ == OptType::Fzf { let result = if opt.type_ == OptType::Fzf {
external::fzf(FzfOpt { cwd }).await external::fzf(FzfOpt { cwd }).await
@ -52,9 +52,9 @@ impl Tab {
}; };
if opt.type_ == OptType::Fzf && !ends_with_slash(&url) { if opt.type_ == OptType::Fzf && !ends_with_slash(&url) {
Tab::_reveal(&url) TabProxy::reveal(&url)
} else { } else {
Tab::_cd(&url) TabProxy::cd(&url)
} }
}); });
} }

View file

@ -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 { pub struct Opt {
target: Url, target: Url,
@ -21,11 +22,6 @@ impl From<Url> for Opt {
} }
impl Tab { 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<Opt>) { pub fn reveal(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt; let opt = opt.into() as Opt;
@ -35,6 +31,6 @@ impl Tab {
self.cd(parent.clone()); self.cd(parent.clone());
FilesOp::Creating(parent, vec![File::from_dummy(&opt.target)]).emit(); FilesOp::Creating(parent, vec![File::from_dummy(&opt.target)]).emit();
Manager::_hover(Some(opt.target)); ManagerProxy::hover(Some(opt.target));
} }
} }

View file

@ -5,9 +5,10 @@ use tokio::pin;
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt}; use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use yazi_config::popup::InputCfg; use yazi_config::popup::InputCfg;
use yazi_plugin::external; use yazi_plugin::external;
use yazi_proxy::{InputProxy, ManagerProxy, TabProxy};
use yazi_shared::{event::Cmd, fs::FilesOp, render}; use yazi_shared::{event::Cmd, fs::FilesOp, render};
use crate::{input::Input, manager::Manager, tab::Tab}; use crate::tab::Tab;
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq)]
pub enum OptType { pub enum OptType {
@ -59,7 +60,7 @@ impl Tab {
let hidden = self.conf.show_hidden; let hidden = self.conf.show_hidden;
self.search = Some(tokio::spawn(async move { self.search = Some(tokio::spawn(async move {
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!("") }; let Some(Ok(subject)) = input.recv().await else { bail!("") };
cwd = cwd.into_search(subject.clone()); cwd = cwd.into_search(subject.clone());
@ -72,7 +73,7 @@ impl Tab {
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(300)); let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(300));
pin!(rx); 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 { while let Some(chunk) = rx.next().await {
FilesOp::Part(cwd.clone(), chunk, ticket).emit(); FilesOp::Part(cwd.clone(), chunk, ticket).emit();
} }
@ -90,7 +91,7 @@ impl Tab {
if self.current.cwd.is_search() { if self.current.cwd.is_search() {
let rep = self.history_new(&self.current.cwd.to_regular()); let rep = self.history_new(&self.current.cwd.to_regular());
drop(mem::replace(&mut self.current, rep)); drop(mem::replace(&mut self.current, rep));
Manager::_refresh(); ManagerProxy::refresh();
} }
} }
} }

View file

@ -1,8 +1,9 @@
use std::borrow::Cow; use std::borrow::Cow;
use yazi_proxy::AppProxy;
use yazi_shared::{event::Cmd, fs::Url, render, render_and}; use yazi_shared::{event::Cmd, fs::Url, render, render_and};
use crate::{notify::Notify, tab::Tab}; use crate::tab::Tab;
pub struct Opt<'a> { pub struct Opt<'a> {
url: Option<Cow<'a, Url>>, url: Option<Cow<'a, Url>>,
@ -37,10 +38,7 @@ impl<'a> Tab {
}; };
if !b { if !b {
Notify::_push_warn( AppProxy::warn("Select one", "This file cannot be selected, due to path nesting conflict.");
"Select one",
"This file cannot be selected, due to path nesting conflict.",
);
} }
} }
} }

View file

@ -1,6 +1,7 @@
use yazi_proxy::AppProxy;
use yazi_shared::{event::Cmd, render}; use yazi_shared::{event::Cmd, render};
use crate::{notify::Notify, tab::Tab}; use crate::tab::Tab;
pub struct Opt { pub struct Opt {
state: Option<bool>, state: Option<bool>,
@ -35,10 +36,7 @@ impl Tab {
render!(added > 0); render!(added > 0);
if added != addition.len() { if added != addition.len() {
Notify::_push_warn( AppProxy::warn("Select all", "Some files cannot be selected, due to path nesting conflict.");
"Select all",
"Some files cannot be selected, due to path nesting conflict.",
);
} }
} }
} }

View file

@ -1,7 +1,8 @@
use yazi_config::{open::Opener, popup::InputCfg}; use yazi_config::{open::Opener, popup::InputCfg};
use yazi_proxy::{InputProxy, TasksProxy};
use yazi_shared::event::Cmd; use yazi_shared::event::Cmd;
use crate::{input::Input, tab::Tab, tasks::Tasks}; use crate::tab::Tab;
pub struct Opt { pub struct Opt {
exec: String, exec: String,
@ -30,14 +31,14 @@ impl Tab {
tokio::spawn(async move { tokio::spawn(async move {
if !opt.confirm || opt.exec.is_empty() { 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 { match result.recv().await {
Some(Ok(e)) => opt.exec = e, Some(Ok(e)) => opt.exec = e,
_ => return, _ => return,
} }
} }
Tasks::_open_with(selected, Opener { TasksProxy::open_with(selected, Opener {
exec: opt.exec, exec: opt.exec,
block: opt.block, block: opt.block,
orphan: false, orphan: false,

View file

@ -1,9 +1,10 @@
use std::str::FromStr; use std::str::FromStr;
use yazi_config::manager::SortBy; use yazi_config::manager::SortBy;
use yazi_proxy::ManagerProxy;
use yazi_shared::event::Cmd; use yazi_shared::event::Cmd;
use crate::{manager::Manager, tab::Tab, tasks::Tasks}; use crate::{tab::Tab, tasks::Tasks};
impl Tab { impl Tab {
pub fn sort(&mut self, c: Cmd, tasks: &Tasks) { 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.conf.sort_dir_first = c.named.contains_key("dir-first");
self.apply_files_attrs(); self.apply_files_attrs();
Manager::_update_paged(); ManagerProxy::update_paged();
tasks.preload_sorted(&self.current.files); tasks.preload_sorted(&self.current.files);
} }

View file

@ -2,7 +2,7 @@ use std::io::{stdout, Write};
use crossterm::terminal::{disable_raw_mode, enable_raw_mode}; use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use tokio::{io::{stdin, AsyncReadExt}, select, sync::mpsc, time}; use tokio::{io::{stdin, AsyncReadExt}, select, sync::mpsc, time};
use yazi_proxy::App; use yazi_proxy::AppProxy;
use yazi_scheduler::BLOCKER; use yazi_scheduler::BLOCKER;
use yazi_shared::{event::Cmd, term::Term, Defer}; use yazi_shared::{event::Cmd, term::Term, Defer};
@ -27,10 +27,10 @@ impl Tasks {
task.logs.clone() task.logs.clone()
}; };
App::stop().await; AppProxy::stop().await;
let _defer = Defer::new(|| { let _defer = Defer::new(|| {
disable_raw_mode().ok(); disable_raw_mode().ok();
App::resume(); AppProxy::resume();
}); });
Term::clear(&mut stdout()).ok(); Term::clear(&mut stdout()).ok();

View file

@ -1,25 +1,9 @@
use yazi_config::open::Opener; use yazi_proxy::OpenWithOpt;
use yazi_shared::{emit, event::Cmd, fs::Url, Layer};
use crate::tasks::Tasks; use crate::tasks::Tasks;
pub struct Opt {
targets: Vec<Url>,
opener: Opener,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
}
impl Tasks { impl Tasks {
pub fn _open_with(targets: Vec<Url>, opener: Opener) { pub fn open_with(&mut self, opt: impl TryInto<OpenWithOpt>) {
emit!(Call(Cmd::new("open_with").with_data(Opt { targets, opener }), Layer::Tasks));
}
pub fn open_with(&mut self, opt: impl TryInto<Opt>) {
if let Ok(opt) = opt.try_into() { if let Ok(opt) = opt.try_into() {
self.file_open_with(&opt.opener, &opt.targets); self.file_open_with(&opt.opener, &opt.targets);
} }

View file

@ -43,6 +43,7 @@ impl Signals {
#[cfg(unix)] #[cfg(unix)]
fn spawn_system_task(&self) -> Result<JoinHandle<()>> { fn spawn_system_task(&self) -> Result<JoinHandle<()>> {
use libc::{SIGCONT, SIGHUP, SIGINT, SIGQUIT, SIGTERM}; use libc::{SIGCONT, SIGHUP, SIGINT, SIGQUIT, SIGTERM};
use yazi_proxy::AppProxy;
use yazi_scheduler::BLOCKER; use yazi_scheduler::BLOCKER;
let mut signals = signal_hook_tokio::Signals::new([ let mut signals = signal_hook_tokio::Signals::new([
@ -65,7 +66,7 @@ impl Signals {
break; break;
} }
} }
SIGCONT => yazi_proxy::App::resume(), SIGCONT => AppProxy::resume(),
_ => {} _ => {}
} }
} }

View file

@ -13,4 +13,5 @@ yazi-config = { path = "../yazi-config", version = "0.2.3" }
yazi-shared = { path = "../yazi-shared", version = "0.2.3" } yazi-shared = { path = "../yazi-shared", version = "0.2.3" }
# External dependencies # External dependencies
tokio = { version = "^1", features = [ "parking_lot" ] } anyhow = "^1"
tokio = { version = "^1", features = [ "parking_lot" ] }

View file

@ -1,16 +1,30 @@
use tokio::sync::oneshot; use tokio::sync::oneshot;
use yazi_shared::{emit, event::Cmd, Layer}; use yazi_shared::{emit, event::Cmd, Layer};
pub struct App; pub struct AppProxy;
impl App { impl AppProxy {
#[inline]
pub async fn stop() { pub async fn stop() {
let (tx, rx) = oneshot::channel::<()>(); let (tx, rx) = oneshot::channel::<()>();
emit!(Call(Cmd::new("stop").with_data(tx), Layer::App)); emit!(Call(Cmd::new("stop").with_data(tx), Layer::App));
rx.await.ok(); rx.await.ok();
} }
#[inline]
pub fn resume() { pub fn resume() {
emit!(Call(Cmd::new("resume"), Layer::App)); 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
));
}
} }

View file

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

30
yazi-proxy/src/input.rs Normal file
View file

@ -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<Result<String, InputError>>,
}
impl TryFrom<Cmd> for InputOpt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
}
pub struct InputProxy;
impl InputProxy {
#[inline]
pub fn show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> {
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));
}
}

View file

@ -1,3 +1,15 @@
mod app; mod app;
mod completion;
mod input;
mod manager;
mod select;
mod tab;
mod tasks;
pub use app::*; pub use app::*;
pub use completion::*;
pub use input::*;
pub use manager::*;
pub use select::*;
pub use tab::*;
pub use tasks::*;

60
yazi-proxy/src/manager.rs Normal file
View file

@ -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<Cmd> 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<Url>) {
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<Url>, 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
));
}
}

25
yazi-proxy/src/select.rs Normal file
View file

@ -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<anyhow::Result<usize>>,
}
impl TryFrom<Cmd> for SelectOpt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
}
pub struct SelectProxy;
impl SelectProxy {
#[inline]
pub async fn show(cfg: SelectCfg) -> anyhow::Result<usize> {
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))
}
}

15
yazi-proxy/src/tab.rs Normal file
View file

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

22
yazi-proxy/src/tasks.rs Normal file
View file

@ -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<Url>,
pub opener: Opener,
}
impl TryFrom<Cmd> for OpenWithOpt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
}
impl TasksProxy {
#[inline]
pub fn open_with(targets: Vec<Url>, opener: Opener) {
emit!(Call(Cmd::new("open_with").with_data(OpenWithOpt { targets, opener }), Layer::Tasks));
}
}

View file

@ -1,7 +1,7 @@
use anyhow::Result; use anyhow::Result;
use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::mpsc}; use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::mpsc};
use yazi_plugin::external::{self, ShellOpt}; use yazi_plugin::external::{self, ShellOpt};
use yazi_proxy::App; use yazi_proxy::AppProxy;
use super::ProcessOpOpen; use super::ProcessOpOpen;
use crate::{TaskProg, BLOCKER}; use crate::{TaskProg, BLOCKER};
@ -17,7 +17,7 @@ impl Process {
let opt = ShellOpt::from(&mut task); let opt = ShellOpt::from(&mut task);
if task.block { if task.block {
let _guard = BLOCKER.acquire().await.unwrap(); let _guard = BLOCKER.acquire().await.unwrap();
App::stop().await; AppProxy::stop().await;
match external::shell(opt) { match external::shell(opt) {
Ok(mut child) => { Ok(mut child) => {
@ -29,7 +29,7 @@ impl Process {
self.fail(task.id, format!("Failed to spawn process: {e}"))?; self.fail(task.id, format!("Failed to spawn process: {e}"))?;
} }
} }
return Ok(App::resume()); return Ok(AppProxy::resume());
} }
if task.orphan { if task.orphan {