feat: add fd, rg external tools

This commit is contained in:
sxyazi 2023-07-09 19:12:58 +08:00
parent fd0966de3f
commit a72acf6fd3
No known key found for this signature in database
7 changed files with 124 additions and 7 deletions

View File

@ -10,8 +10,8 @@ Before getting started, ensure that the following dependencies are installed on
- jq (optional, for JSON preview)
- ffmpegthumbnailer (optional, for video thumbnails)
- fzf (optional, for fuzzy search)
- rg (optional, for fuzzy search)
- fd (optional, for file searching)
- rg (optional, for content searching)
- zoxide (optional, for directory jumping)
Execute the following commands to clone the project and build Yazi:
@ -30,11 +30,11 @@ cargo build --release
## TODO
- Add example config for general usage, currently please see my [another repo](https://github.com/sxyazi/dotfiles/tree/main/yazi) instead
- Integration with zoxide for fast directory navigation
- Integration with fzf, rg for fuzzy file searching
- Support for Überzug++ for image previews with X11/wayland environment
- Batch renaming support
- [ ] Add example config for general usage, currently please see my [another repo](https://github.com/sxyazi/dotfiles/tree/main/yazi) instead
- [ ] Integration with zoxide for fast directory navigation
- [ ] Integration with fd, rg for fuzzy file searching
- [ ] Support for Überzug++ for image previews with X11/wayland environment
- [ ] Batch renaming support
## License

38
src/core/external/fd.rs vendored Normal file
View File

@ -0,0 +1,38 @@
use std::{path::PathBuf, process::Stdio, time::Duration};
use anyhow::Result;
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::UnboundedReceiver, task::JoinHandle};
use crate::misc::DelayedBuffer;
pub struct FdOpt {
pub cwd: PathBuf,
pub hidden: bool,
pub regex: bool,
pub subject: String,
}
pub fn fd(opt: FdOpt) -> Result<(JoinHandle<()>, UnboundedReceiver<Vec<String>>)> {
let mut child = Command::new("fd")
.arg("--base-directory")
.arg(&opt.cwd)
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
.arg(if opt.regex { "--regex" } else { "--glob" })
.arg(&opt.subject)
.kill_on_drop(true)
.stdout(Stdio::piped())
.spawn()?;
drop(child.stderr.take());
let mut it = BufReader::new(child.stdout.take().unwrap()).lines();
let (mut buf, rx) = DelayedBuffer::new(Duration::from_millis(100));
let handle = tokio::spawn(async move {
while let Ok(Some(line)) = it.next_line().await {
buf.push(line);
}
child.wait().await.ok();
});
Ok((handle, rx))
}

5
src/core/external/mod.rs vendored Normal file
View File

@ -0,0 +1,5 @@
mod fd;
mod rg;
pub use fd::*;
pub use rg::*;

36
src/core/external/rg.rs vendored Normal file
View File

@ -0,0 +1,36 @@
use std::{path::PathBuf, process::Stdio, time::Duration};
use anyhow::Result;
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::UnboundedReceiver, task::JoinHandle};
use crate::misc::DelayedBuffer;
pub struct RgOpt {
pub cwd: PathBuf,
pub hidden: bool,
pub subject: String,
}
pub async fn rg(opt: RgOpt) -> Result<(JoinHandle<()>, UnboundedReceiver<Vec<String>>)> {
let mut child = Command::new("rg")
.current_dir(&opt.cwd)
.args(&["--color=never", "--files-with-matches", "--smart-case"])
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
.arg(&opt.subject)
.kill_on_drop(true)
.stdout(Stdio::piped())
.spawn()?;
drop(child.stderr.take());
let mut it = BufReader::new(child.stdout.take().unwrap()).lines();
let (mut buf, rx) = DelayedBuffer::new(Duration::from_millis(100));
let handle = tokio::spawn(async move {
while let Ok(Some(line)) = it.next_line().await {
buf.push(line);
}
child.wait().await.ok();
});
Ok((handle, rx))
}

View File

@ -1,5 +1,6 @@
mod adapter;
mod event;
pub mod external;
mod input;
mod manager;
mod tasks;

35
src/misc/buffer.rs Normal file
View File

@ -0,0 +1,35 @@
use std::time::Duration;
use tokio::{sync::mpsc::{self, UnboundedReceiver, UnboundedSender}, time::Instant};
pub struct DelayedBuffer<T> {
buf: Vec<T>,
tx: UnboundedSender<Vec<T>>,
last: Instant,
interval: Duration,
}
impl<T> DelayedBuffer<T> {
pub fn new(interval: Duration) -> (Self, UnboundedReceiver<Vec<T>>) {
let (tx, rx) = mpsc::unbounded_channel();
(Self { buf: Vec::new(), tx, last: Instant::now() - interval, interval }, rx)
}
pub fn push(&mut self, item: T) {
self.buf.push(item);
if self.last.elapsed() >= self.interval {
self.last = Instant::now();
self.tx.send(self.buf.drain(..).collect()).ok();
}
}
pub fn flush(&mut self) {
if !self.buf.is_empty() {
self.tx.send(self.buf.drain(..).collect()).ok();
}
}
}
impl<T> Drop for DelayedBuffer<T> {
fn drop(&mut self) { self.flush(); }
}

View File

@ -1,7 +1,9 @@
mod buffer;
mod chars;
mod defer;
mod fns;
pub use buffer::*;
pub use chars::*;
pub use defer::*;
pub use fns::*;