feat: new search_do command to make it easier to achieve a flat view (#1431)

This commit is contained in:
三咲雅 · Misaki Masa 2024-08-07 21:36:55 +08:00 committed by GitHub
parent 5df6873957
commit 1e08e09899
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 123 additions and 72 deletions

5
Cargo.lock generated
View File

@ -2751,9 +2751,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uzers"
version = "0.12.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d85875e16d59b3b1549efce83ff8251a64923b03bef94add0a1862847448de4"
checksum = "4df81ff504e7d82ad53e95ed1ad5b72103c11253f39238bcc0235b90768a97dd"
dependencies = [
"libc",
"log",
@ -3418,6 +3418,7 @@ version = "0.3.0"
dependencies = [
"anyhow",
"mlua",
"shell-words",
"tokio",
"yazi-config",
"yazi-shared",

View File

@ -75,7 +75,7 @@ keymap = [
{ on = ".", run = "hidden toggle", desc = "Toggle the visibility of hidden files" },
{ on = "s", run = "search fd", desc = "Search files by name using fd" },
{ on = "S", run = "search rg", desc = "Search files by content using ripgrep" },
{ on = "<C-s>", run = "search none", desc = "Cancel the ongoing search" },
{ on = "<C-s>", run = "escape --search", desc = "Cancel the ongoing search" },
{ on = "z", run = "plugin zoxide", desc = "Jump to a directory using zoxide" },
{ on = "Z", run = "plugin fzf", desc = "Jump to a directory or reveal a file using fzf" },

View File

@ -92,12 +92,10 @@ impl Tab {
}
pub fn escape_search(&mut self) -> bool {
if !self.current.cwd.is_search() {
return false;
}
let b = self.current.cwd.is_search();
self.search_stop();
render_and!(true)
render_and!(b)
}
pub fn try_escape_visual(&mut self) -> bool {

View File

@ -1,65 +1,22 @@
use std::{fmt::Display, mem, time::Duration};
use std::{mem, time::Duration};
use anyhow::bail;
use tokio::pin;
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
use tracing::error;
use yazi_config::popup::InputCfg;
use yazi_plugin::external;
use yazi_proxy::{AppProxy, InputProxy, ManagerProxy, TabProxy};
use yazi_shared::{event::Cmd, fs::FilesOp, render};
use yazi_proxy::{options::{SearchOpt, SearchOptVia}, AppProxy, InputProxy, ManagerProxy, TabProxy};
use yazi_shared::fs::FilesOp;
use crate::tab::Tab;
#[derive(PartialEq, Eq)]
pub enum OptType {
None,
Rg,
Fd,
}
impl From<String> for OptType {
fn from(value: String) -> Self {
match value.as_str() {
"rg" => Self::Rg,
"fd" => Self::Fd,
_ => Self::None,
}
}
}
impl Display for OptType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Rg => "rg",
Self::Fd => "fd",
Self::None => "none",
})
}
}
pub struct Opt {
pub type_: OptType,
pub args: Vec<String>,
}
impl TryFrom<Cmd> for Opt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
Ok(Self {
type_: c.take_first_str().unwrap_or_default().into(),
args: shell_words::split(c.str("args").unwrap_or_default()).map_err(|_| ())?,
})
}
}
impl Tab {
pub fn search(&mut self, opt: impl TryInto<Opt>) {
let Ok(opt) = opt.try_into() else {
pub fn search(&mut self, opt: impl TryInto<SearchOpt>) {
let Ok(mut opt) = opt.try_into() else {
return AppProxy::notify_error("Invalid `search` option", "Failed to parse search option");
};
if opt.type_ == OptType::None {
if opt.via == SearchOptVia::None {
return self.search_stop();
}
@ -67,18 +24,45 @@ impl Tab {
handle.abort();
}
tokio::spawn(async move {
let mut input =
InputProxy::show(InputCfg::search(&opt.via.to_string()).with_value(opt.subject));
if let Some(Ok(subject)) = input.recv().await {
opt.subject = subject;
TabProxy::search_do(opt);
}
});
}
pub fn search_do(&mut self, opt: impl TryInto<SearchOpt>) {
let Ok(opt) = opt.try_into() else {
return error!("Failed to parse search option for `search_do`");
};
if let Some(handle) = self.search.take() {
handle.abort();
}
let mut cwd = self.current.cwd.clone();
let hidden = self.conf.show_hidden;
self.search = Some(tokio::spawn(async move {
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());
let rx = if opt.type_ == OptType::Rg {
external::rg(external::RgOpt { cwd: cwd.clone(), hidden, subject, args: opt.args })
cwd = cwd.into_search(opt.subject.clone());
let rx = if opt.via == SearchOptVia::Rg {
external::rg(external::RgOpt {
cwd: cwd.clone(),
hidden,
subject: opt.subject,
args: opt.args,
})
} else {
external::fd(external::FdOpt { cwd: cwd.clone(), hidden, subject, args: opt.args })
external::fd(external::FdOpt {
cwd: cwd.clone(),
hidden,
subject: opt.subject,
args: opt.args,
})
}?;
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(300));
@ -89,10 +73,9 @@ impl Tab {
FilesOp::Part(cwd.clone(), chunk, ticket).emit();
}
FilesOp::Done(cwd, None, ticket).emit();
Ok(())
}));
render!();
}
pub(super) fn search_stop(&mut self) {

View File

@ -31,4 +31,4 @@ tracing = { workspace = true }
vergen-gitcl = { version = "1.0.0", features = [ "build" ] }
[target."cfg(unix)".dependencies]
uzers = "0.12.0"
uzers = "0.12.1"

View File

@ -110,6 +110,7 @@ impl<'a> Executor<'a> {
on!(ACTIVE, hidden);
on!(ACTIVE, linemode);
on!(ACTIVE, search);
on!(ACTIVE, search_do);
// Filter
on!(ACTIVE, filter);

View File

@ -41,7 +41,7 @@ unicode-width = { workspace = true }
yazi-prebuild = "0.1.2"
[target."cfg(unix)".dependencies]
uzers = "0.12.0"
uzers = "0.12.1"
[target."cfg(windows)".dependencies]
clipboard-win = "5.4.0"

View File

@ -17,6 +17,7 @@ yazi-config = { path = "../yazi-config", version = "0.3.0" }
yazi-shared = { path = "../yazi-shared", version = "0.3.0" }
# External dependencies
anyhow = { workspace = true }
mlua = { workspace = true }
tokio = { workspace = true }
anyhow = { workspace = true }
mlua = { workspace = true }
shell-words = { workspace = true }
tokio = { workspace = true }

View File

@ -1,7 +1,9 @@
mod notify;
mod open;
mod process;
mod search;
pub use notify::*;
pub use open::*;
pub use process::*;
pub use search::*;

View File

@ -0,0 +1,53 @@
use std::fmt::Display;
use yazi_shared::event::Cmd;
pub struct SearchOpt {
pub via: SearchOptVia,
pub subject: String,
pub args: Vec<String>,
pub args_raw: String,
}
impl TryFrom<Cmd> for SearchOpt {
type Error = ();
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
Ok(Self {
// TODO: remove `c.take_first_str()` in the future
via: c.take_str("via").or_else(|| c.take_first_str()).unwrap_or_default().into(),
subject: c.take_first_str().unwrap_or_default(),
args: shell_words::split(c.str("args").unwrap_or_default()).map_err(|_| ())?,
args_raw: c.take_str("args").unwrap_or_default(),
})
}
}
// Via
#[derive(PartialEq, Eq)]
pub enum SearchOptVia {
// TODO: remove `None` in the future
None,
Rg,
Fd,
}
impl From<String> for SearchOptVia {
fn from(value: String) -> Self {
match value.as_str() {
"rg" => Self::Rg,
"fd" => Self::Fd,
_ => Self::None,
}
}
}
impl Display for SearchOptVia {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Rg => "rg",
Self::Fd => "fd",
Self::None => "none",
})
}
}

View File

@ -1,5 +1,7 @@
use yazi_shared::{emit, event::Cmd, fs::Url, Layer};
use crate::options::SearchOpt;
pub struct TabProxy;
impl TabProxy {
@ -12,4 +14,12 @@ impl TabProxy {
pub fn reveal(target: &Url) {
emit!(Call(Cmd::args("reveal", vec![target.to_string()]), Layer::Manager));
}
#[inline]
pub fn search_do(opt: SearchOpt) {
emit!(Call(
Cmd::args("search_do", vec![opt.subject]).with("via", opt.via).with("args", opt.args_raw),
Layer::Manager
));
}
}

View File

@ -167,6 +167,7 @@ impl Url {
#[inline]
pub fn into_regular(mut self) -> Self {
self.scheme = UrlScheme::Regular;
self.frag = String::new();
self
}
@ -192,6 +193,7 @@ impl Url {
#[inline]
pub fn into_archive(mut self) -> Self {
self.scheme = UrlScheme::Archive;
self.frag = String::new();
self
}