A file-based task manager
1use crate::errors::{Error, Result};
2use std::ffi::OsStr;
3use std::fmt::Display;
4use std::io::Write;
5use std::process::{Command, Stdio};
6use std::str::FromStr;
7
8/// Sends each item as a line to stdin to the `fzf` command and returns the selected item's string
9/// representation as output
10pub fn select<I, O, S>(
11 input: impl IntoIterator<Item = I>,
12 extra: impl IntoIterator<Item = S>,
13) -> Result<Option<O>>
14where
15 O: FromStr,
16 I: Display,
17 Error: From<<O as FromStr>::Err>,
18 S: AsRef<OsStr>,
19{
20 let mut command = Command::new("fzf");
21 let mut child = command
22 .args(extra)
23 .arg("--read0")
24 .stderr(Stdio::inherit())
25 .stdin(Stdio::piped())
26 .stdout(Stdio::piped())
27 .spawn()?;
28 // unwrap: this can never fail
29 let child_in = child.stdin.as_mut().unwrap();
30 for item in input.into_iter() {
31 write!(child_in, "{item}\0")?;
32 }
33 let output = child.wait_with_output()?;
34 if output.stdout.is_empty() {
35 Ok(None)
36 } else {
37 Ok(Some(String::from_utf8(output.stdout)?.parse()?))
38 }
39}