mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
125 lines
3 KiB
Rust
125 lines
3 KiB
Rust
use std::{borrow::Cow, time::Duration};
|
|
|
|
use anyhow::Result;
|
|
use tokio::pin;
|
|
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
|
use yazi_config::popup::InputCfg;
|
|
use yazi_core::mgr::SearchVia;
|
|
use yazi_fs::{FilesOp, cha::Cha};
|
|
use yazi_macro::{act, succ};
|
|
use yazi_parser::{VoidForm, mgr::{CdSource, SearchForm}};
|
|
use yazi_plugin::external;
|
|
use yazi_proxy::{InputProxy, MgrProxy};
|
|
use yazi_scheduler::NotifyProxy;
|
|
use yazi_shared::{data::Data, url::{AsUrl, UrlLike}};
|
|
use yazi_widgets::input::InputEvent;
|
|
|
|
use crate::{Actor, Ctx};
|
|
|
|
pub struct Search;
|
|
|
|
impl Actor for Search {
|
|
type Form = SearchForm;
|
|
|
|
const NAME: &str = "search";
|
|
|
|
fn act(cx: &mut Ctx, Self::Form { mut opt }: Self::Form) -> Result<Data> {
|
|
if let Some(handle) = cx.tab_mut().search.take() {
|
|
handle.abort();
|
|
}
|
|
|
|
let mut input = InputProxy::show(InputCfg::search(opt.via.into()).with_value(&*opt.subject));
|
|
|
|
tokio::spawn(async move {
|
|
if let Some(InputEvent::Submit(subject)) = input.recv().await {
|
|
opt.subject = Cow::Owned(subject);
|
|
MgrProxy::search_do(opt);
|
|
}
|
|
});
|
|
succ!();
|
|
}
|
|
}
|
|
|
|
// --- Do
|
|
pub struct SearchDo;
|
|
|
|
impl Actor for SearchDo {
|
|
type Form = SearchForm;
|
|
|
|
const NAME: &str = "search_do";
|
|
|
|
fn act(cx: &mut Ctx, Self::Form { opt }: Self::Form) -> Result<Data> {
|
|
let tab = cx.tab_mut();
|
|
if let Some(handle) = tab.search.take() {
|
|
handle.abort();
|
|
}
|
|
|
|
let hidden = tab.pref.show_hidden;
|
|
let r#in = opt.r#in.as_ref().map_or_else(|| tab.cwd().as_url(), |u| u.as_url());
|
|
let Ok(cwd) = r#in.to_search(&opt.subject) else {
|
|
succ!(NotifyProxy::push_warn("Search", "Only local filesystem searches are supported"));
|
|
};
|
|
|
|
tab.search = Some(tokio::spawn(async move {
|
|
let rx = match opt.via {
|
|
SearchVia::Rg => external::rg(external::RgOpt {
|
|
cwd: cwd.clone(),
|
|
hidden,
|
|
subject: opt.subject.into_owned(),
|
|
args: opt.args,
|
|
}),
|
|
SearchVia::Rga => external::rga(external::RgaOpt {
|
|
cwd: cwd.clone(),
|
|
hidden,
|
|
subject: opt.subject.into_owned(),
|
|
args: opt.args,
|
|
}),
|
|
SearchVia::Fd => external::fd(external::FdOpt {
|
|
cwd: cwd.clone(),
|
|
hidden,
|
|
subject: opt.subject.into_owned(),
|
|
args: opt.args,
|
|
}),
|
|
}?;
|
|
|
|
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(5000, Duration::from_millis(500));
|
|
pin!(rx);
|
|
|
|
let ((), ticket) = (MgrProxy::cd(&cwd), FilesOp::prepare(&cwd));
|
|
while let Some(chunk) = rx.next().await {
|
|
FilesOp::Part(cwd.clone(), chunk, ticket).emit();
|
|
}
|
|
FilesOp::Done(cwd, Cha::default(), ticket).emit();
|
|
|
|
Ok(())
|
|
}));
|
|
|
|
succ!();
|
|
}
|
|
}
|
|
|
|
// --- Stop
|
|
pub struct SearchStop;
|
|
|
|
impl Actor for SearchStop {
|
|
type Form = VoidForm;
|
|
|
|
const NAME: &str = "search_stop";
|
|
|
|
fn act(cx: &mut Ctx, _: Self::Form) -> Result<Data> {
|
|
let tab = cx.tab_mut();
|
|
if let Some(handle) = tab.search.take() {
|
|
handle.abort();
|
|
}
|
|
|
|
if !tab.cwd().is_search() {
|
|
succ!();
|
|
}
|
|
|
|
if let Some(u) = tab.backstack.current().cloned() {
|
|
act!(mgr:cd, cx, (u, CdSource::Escape))
|
|
} else {
|
|
act!(mgr:cd, cx, (tab.cwd().to_regular()?, CdSource::Escape))
|
|
}
|
|
}
|
|
}
|