2021-09-13 08:01:58 +00:00
|
|
|
use std::io;
|
|
|
|
|
use std::process::{Child, ChildStdin, Command, Stdio};
|
2020-10-26 17:55:04 +00:00
|
|
|
|
|
|
|
|
use anyhow::{bail, Context, Result};
|
|
|
|
|
|
2021-09-13 08:01:58 +00:00
|
|
|
use crate::config;
|
|
|
|
|
use crate::error::SilentExit;
|
2020-10-26 17:55:04 +00:00
|
|
|
|
|
|
|
|
pub struct Fzf {
|
|
|
|
|
child: Child,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Fzf {
|
2021-04-28 20:01:00 +00:00
|
|
|
pub fn new(multiple: bool) -> Result<Self> {
|
2020-10-26 17:55:04 +00:00
|
|
|
let mut command = Command::new("fzf");
|
2021-04-28 20:01:00 +00:00
|
|
|
if multiple {
|
|
|
|
|
command.arg("-m");
|
|
|
|
|
}
|
2021-05-17 16:16:42 +00:00
|
|
|
command.arg("-n2..").stdin(Stdio::piped()).stdout(Stdio::piped());
|
2021-05-27 06:09:57 +00:00
|
|
|
if let Some(fzf_opts) = config::fzf_opts() {
|
2020-10-26 17:55:04 +00:00
|
|
|
command.env("FZF_DEFAULT_OPTS", fzf_opts);
|
2021-11-30 21:48:33 +00:00
|
|
|
} else {
|
|
|
|
|
command.args(&[
|
|
|
|
|
"--bind=ctrl-z:ignore",
|
|
|
|
|
"--exit-0",
|
|
|
|
|
"--height=35%",
|
|
|
|
|
"--inline-info",
|
|
|
|
|
"--no-sort",
|
|
|
|
|
"--reverse",
|
|
|
|
|
"--select-1",
|
|
|
|
|
]);
|
|
|
|
|
if cfg!(unix) {
|
|
|
|
|
command.arg("--preview=ls -p {2}");
|
|
|
|
|
}
|
2020-10-26 17:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
2021-05-07 07:34:44 +00:00
|
|
|
let child = match command.spawn() {
|
|
|
|
|
Ok(child) => child,
|
|
|
|
|
Err(e) if e.kind() == io::ErrorKind::NotFound => {
|
|
|
|
|
bail!("could not find fzf, is it installed?")
|
|
|
|
|
}
|
|
|
|
|
Err(e) => Err(e).context("could not launch fzf")?,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(Fzf { child })
|
2020-10-26 17:55:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn stdin(&mut self) -> &mut ChildStdin {
|
2021-09-13 08:01:58 +00:00
|
|
|
// unwrap is safe here because command.stdin() has been piped.
|
2020-10-26 17:55:04 +00:00
|
|
|
self.child.stdin.as_mut().unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn wait_select(self) -> Result<String> {
|
2021-05-17 16:16:42 +00:00
|
|
|
let output = self.child.wait_with_output().context("wait failed on fzf")?;
|
2020-10-26 17:55:04 +00:00
|
|
|
|
|
|
|
|
match output.status.code() {
|
|
|
|
|
// normal exit
|
|
|
|
|
Some(0) => String::from_utf8(output.stdout).context("invalid unicode in fzf output"),
|
|
|
|
|
|
|
|
|
|
// no match
|
|
|
|
|
Some(1) => bail!("no match found"),
|
|
|
|
|
|
|
|
|
|
// error
|
|
|
|
|
Some(2) => bail!("fzf returned an error"),
|
|
|
|
|
|
|
|
|
|
// terminated by a signal
|
|
|
|
|
Some(code @ 130) => bail!(SilentExit { code }),
|
|
|
|
|
Some(128..=254) | None => bail!("fzf was terminated"),
|
|
|
|
|
|
|
|
|
|
// unknown
|
|
|
|
|
_ => bail!("fzf returned an unknown error"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|