1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
use figment::Provider;
use std::{
ffi::OsStr,
io::Write,
ops::{Deref, DerefMut},
os::unix::prelude::OsStrExt,
process::{Child, Command, Output, Stdio},
};
pub use config::Config;
pub use error::{Error, Result};
mod config;
mod error;
pub struct Finder {
program: String,
args: Vec<String>,
}
impl Finder {
pub fn new() -> Result<Self> {
Self::from_provider(Config::figment())
}
/// Extract `Config` from `provider` to construct new `Finder`
pub fn from_provider<T: Provider>(provider: T) -> Result<Self> {
Config::extract(&provider)
.map(|config| Finder {
program: config.program,
args: config.args,
})
.map_err(Into::into)
}
pub fn spawn(self) -> Result<FinderChild> {
Command::new(self.program)
.args(self.args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.map(FinderChild)
.map_err(Into::into)
}
}
pub struct FinderChild(Child);
impl FinderChild {
pub fn find<V, I>(mut self, items: V) -> Result<Output>
where
V: IntoIterator<Item = I>,
I: AsRef<OsStr>,
{
let stdin = self.stdin.as_mut().ok_or(Error::Stdin)?;
items.into_iter().try_for_each(|item| -> Result<()> {
stdin.write_all(item.as_ref().as_bytes())?;
stdin.write_all("\n".as_bytes()).map_err(From::from)
})?;
self.0.wait_with_output().map_err(Into::into)
}
}
impl Deref for FinderChild {
type Target = Child;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for FinderChild {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_output() {
let items = Vec::from(["item1"]);
let finder = Finder {
program: "fzf".into(),
args: ["-1".into()].into(),
};
let selected = finder.spawn().unwrap().find(items).unwrap().stdout;
assert_eq!(selected.as_slice(), "item1\n".as_bytes())
}
#[test]
#[ignore]
fn test_selection() {
let items = Vec::from(["item1", "item2", "item3", "item4"]);
let finder = Finder {
program: "fzf".into(),
args: [].into(),
};
let selected = finder.spawn().unwrap().find(items).unwrap().stdout;
assert_eq!(selected.as_slice(), "item1\n".as_bytes())
}
}
|