From 0001feb24b75f9d9bd937f5c3c6bfd8179e271b9 Mon Sep 17 00:00:00 2001 From: phiresky Date: Mon, 8 Jun 2020 14:00:18 +0200 Subject: [PATCH] add experimental rga-fzf binary --- src/args.rs | 6 ++++ src/bin/rga-fzf.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++ src/bin/rga.rs | 10 ++++++- 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/bin/rga-fzf.rs diff --git a/src/args.rs b/src/args.rs index a1807fd..1e4248e 100644 --- a/src/args.rs +++ b/src/args.rs @@ -147,6 +147,12 @@ pub struct RgaArgs { )] pub max_archive_recursion: i32, + #[serde(skip)] + #[structopt(long = "--rga-fzf-path", require_equals = true, hidden = true)] + /// same as passing path directly, except if argument is empty + /// kinda hacky, but if no file is found, fzf calls rga with empty string as path, which causes No such file or directory from rg. So filter those cases and return specially + pub fzf_path: Option, + // these arguments stop the process, so don't serialize them #[serde(skip)] #[structopt(long = "--rga-list-adapters", help = "List all known adapters")] diff --git a/src/bin/rga-fzf.rs b/src/bin/rga-fzf.rs new file mode 100644 index 0000000..0fa6fea --- /dev/null +++ b/src/bin/rga-fzf.rs @@ -0,0 +1,75 @@ +use anyhow::Context; +use rga::adapters::spawning::map_exe_error; +use ripgrep_all as rga; + +use std::process::{Command, Stdio}; + +fn main() -> anyhow::Result<()> { + env_logger::init(); + let mut passthrough_args: Vec = std::env::args().skip(1).collect(); + let inx = passthrough_args.iter().position(|e| !e.starts_with("-")); + let initial_query = if let Some(inx) = inx { + passthrough_args.remove(inx) + } else { + "".to_string() + }; + + let exe = std::env::current_exe().context("Could not get executable location")?; + let preproc_exe = exe.with_file_name("rga"); + let preproc_exe = preproc_exe + .to_str() + .context("rga executable is in non-unicode path")?; + + let rg_prefix = format!( + "{} --files-with-matches --rga-cache-max-blob-len=10M", + preproc_exe + ); + + let child = Command::new("fzf") + .arg(format!( + "--preview={} --pretty --context 5 {{q}} --rga-fzf-path=_{{}}", + preproc_exe + )) + .arg("--phony") + .arg("--query") + .arg(&initial_query) + .arg("--print-query") + .arg(format!("--bind=change:reload: {} {{q}}", rg_prefix)) + .env( + "FZF_DEFAULT_COMMAND", + format!("{} '{}'", rg_prefix, &initial_query), + ) + .stdout(Stdio::piped()) + .spawn() + .map_err(|e| map_exe_error(e, "fzf", "Please make sure you have fzf installed."))?; + + let output = child.wait_with_output()?; + let mut x = output.stdout.split(|e| e == &b'\n'); + let final_query = + std::str::from_utf8(x.next().context("fzf output empty")?).context("fzf query not utf8")?; + let selected_file = std::str::from_utf8(x.next().context("fzf output not two line")?) + .context("fzf ofilename not utf8")?; + println!("query='{}', file='{}'", final_query, selected_file); + + if selected_file.ends_with(".pdf") { + use std::io::ErrorKind::*; + let worked = Command::new("evince") + .arg("--find") + .arg(final_query) + .arg(selected_file) + .spawn() + .map_or_else( + |err| match err.kind() { + NotFound => Ok(false), + _ => Err(err), + }, + |_| Ok(true), + )?; + if worked { + return Ok(()); + } + } + Command::new("xdg-open").arg(selected_file).spawn()?; + + Ok(()) +} diff --git a/src/bin/rga.rs b/src/bin/rga.rs index 3946653..a7c4fa8 100644 --- a/src/bin/rga.rs +++ b/src/bin/rga.rs @@ -12,7 +12,7 @@ use std::process::Command; fn main() -> anyhow::Result<()> { env_logger::init(); - let (args, passthrough_args) = split_args()?; + let (args, mut passthrough_args) = split_args()?; if args.list_adapters { let (enabled_adapters, disabled_adapters) = get_all_adapters(); @@ -62,6 +62,14 @@ fn main() -> anyhow::Result<()> { } return Ok(()); } + if let Some(path) = args.fzf_path { + if path == "_" { + // fzf found no result, ignore everything and return + println!("[no file found]"); + return Ok(()); + } + passthrough_args.push(std::ffi::OsString::from(&path[1..])); + } if passthrough_args.len() == 0 { // rg would show help. Show own help instead.