diff --git a/yazi-core/src/tab/commands/search.rs b/yazi-core/src/tab/commands/search.rs index 69213313..c09d3f76 100644 --- a/yazi-core/src/tab/commands/search.rs +++ b/yazi-core/src/tab/commands/search.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, mem, time::Duration}; +use anyhow::bail; use tokio::pin; use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream}; use tracing::error; @@ -48,20 +49,26 @@ impl Tab { let hidden = self.pref.show_hidden; self.search = Some(tokio::spawn(async move { - let rx = if opt.via == SearchOptVia::Rg { - external::rg(external::RgOpt { + let rx = match opt.via { + SearchOptVia::Rg => external::rg(external::RgOpt { cwd: cwd.clone(), hidden, subject: opt.subject.into_owned(), args: opt.args, - }) - } else { - external::fd(external::FdOpt { + }), + SearchOptVia::Rga => external::rga(external::RgaOpt { cwd: cwd.clone(), hidden, subject: opt.subject.into_owned(), args: opt.args, - }) + }), + SearchOptVia::Fd => external::fd(external::FdOpt { + cwd: cwd.clone(), + hidden, + subject: opt.subject.into_owned(), + args: opt.args, + }), + SearchOptVia::None => bail!("Invalid `via` option for `search` command"), }?; let rx = UnboundedReceiverStream::new(rx).chunks_timeout(5000, Duration::from_millis(500)); diff --git a/yazi-plugin/src/external/mod.rs b/yazi-plugin/src/external/mod.rs index ded3f3b2..f974108b 100644 --- a/yazi-plugin/src/external/mod.rs +++ b/yazi-plugin/src/external/mod.rs @@ -1 +1 @@ -yazi_macro::mod_flat!(fd highlighter rg); +yazi_macro::mod_flat!(fd highlighter rg rga); diff --git a/yazi-plugin/src/external/rga.rs b/yazi-plugin/src/external/rga.rs new file mode 100644 index 00000000..d7e6ac6a --- /dev/null +++ b/yazi-plugin/src/external/rga.rs @@ -0,0 +1,39 @@ +use std::process::Stdio; + +use anyhow::Result; +use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::{self, UnboundedReceiver}}; +use yazi_fs::File; +use yazi_shared::url::Url; + +pub struct RgaOpt { + pub cwd: Url, + pub hidden: bool, + pub subject: String, + pub args: Vec, +} + +pub fn rga(opt: RgaOpt) -> Result> { + let mut child = Command::new("rga") + .args(["--color=never", "--files-with-matches", "--smart-case"]) + .arg(if opt.hidden { "--hidden" } else { "--no-hidden" }) + .args(opt.args) + .arg(opt.subject) + .arg(&opt.cwd) + .kill_on_drop(true) + .stdout(Stdio::piped()) + .stderr(Stdio::null()) + .spawn()?; + + let mut it = BufReader::new(child.stdout.take().unwrap()).lines(); + let (tx, rx) = mpsc::unbounded_channel(); + + tokio::spawn(async move { + while let Ok(Some(line)) = it.next_line().await { + if let Ok(file) = File::from(opt.cwd.join(line)).await { + tx.send(file).ok(); + } + } + child.wait().await.ok(); + }); + Ok(rx) +} diff --git a/yazi-proxy/src/options/search.rs b/yazi-proxy/src/options/search.rs index 03e82c42..50a45460 100644 --- a/yazi-proxy/src/options/search.rs +++ b/yazi-proxy/src/options/search.rs @@ -37,6 +37,7 @@ pub enum SearchOptVia { None, Rg, Fd, + Rga, } impl From<&str> for SearchOptVia { @@ -44,6 +45,7 @@ impl From<&str> for SearchOptVia { match value { "rg" => Self::Rg, "fd" => Self::Fd, + "rga" => Self::Rga, _ => Self::None, } } @@ -54,6 +56,7 @@ impl Display for SearchOptVia { f.write_str(match self { Self::Rg => "rg", Self::Fd => "fd", + Self::Rga => "rga", Self::None => "none", }) }