89 lines
2.3 KiB
Rust
89 lines
2.3 KiB
Rust
use crate::db::{Dir, Epoch};
|
|
use crate::error::SilentExit;
|
|
|
|
use anyhow::{bail, Context, Result};
|
|
|
|
use std::io::Write;
|
|
use std::process::{Child, Command, Stdio};
|
|
use std::str;
|
|
|
|
pub struct Fzf {
|
|
child: Child,
|
|
lines: Vec<String>,
|
|
}
|
|
|
|
impl Fzf {
|
|
pub fn new() -> Result<Self> {
|
|
let child = Command::new("fzf")
|
|
.args(&["-n2..", "--no-sort"])
|
|
.stdin(Stdio::piped())
|
|
.stdout(Stdio::piped())
|
|
.spawn()
|
|
.context("could not launch fzf")?;
|
|
|
|
Ok(Fzf {
|
|
child,
|
|
lines: Vec::new(),
|
|
})
|
|
}
|
|
|
|
pub fn write_dir(&mut self, dir: &Dir, now: Epoch) {
|
|
let frecency = dir.get_frecency(now);
|
|
|
|
let frecency_scaled = if frecency > 9999.0 {
|
|
9999
|
|
} else if frecency > 0.0 {
|
|
frecency as u32
|
|
} else {
|
|
0
|
|
};
|
|
|
|
self.lines
|
|
.push(format!("{:>4} {}", frecency_scaled, dir.path));
|
|
}
|
|
|
|
pub fn wait_selection(mut self) -> Result<Option<String>> {
|
|
// unwrap() is safe here since we have captured `stdin`
|
|
let stdin = self.child.stdin.as_mut().unwrap();
|
|
|
|
self.lines.sort_unstable_by(|line1, line2| line2.cmp(line1));
|
|
|
|
for line in self.lines.iter() {
|
|
writeln!(stdin, "{}", line).context("could not write into fzf stdin")?;
|
|
}
|
|
|
|
let output = self
|
|
.child
|
|
.wait_with_output()
|
|
.context("wait failed on fzf")?;
|
|
|
|
match output.status.code() {
|
|
// normal exit
|
|
Some(0) => {
|
|
let path_bytes = output
|
|
.stdout
|
|
.get(12..output.stdout.len().saturating_sub(1))
|
|
.context("fzf returned invalid output")?;
|
|
|
|
let path_str =
|
|
str::from_utf8(path_bytes).context("invalid utf-8 sequence in fzf output")?;
|
|
|
|
Ok(Some(path_str.to_string()))
|
|
}
|
|
|
|
// no match
|
|
Some(1) => Ok(None),
|
|
|
|
// 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"),
|
|
}
|
|
}
|
|
}
|