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
//! # Non-blocking `find`-style picker
//!
//! Iterate over directories to populate the picker, but do not block so that
//! matching can be done while the picker is populated.
use std::{borrow::Cow, env::args, io, path::PathBuf, process::exit, thread::spawn};
use ignore::{DirEntry, WalkBuilder, WalkState};
use nucleo_picker::{PickerOptions, Render};
pub struct DirEntryRender;
impl Render<DirEntry> for DirEntryRender {
type Str<'a> = Cow<'a, str>;
/// Render a `DirEntry` using its internal path buffer.
fn render<'a>(&self, value: &'a DirEntry) -> Self::Str<'a> {
value.path().to_string_lossy()
}
}
fn main() -> io::Result<()> {
let mut picker = PickerOptions::default()
// Optimize scoring algorithm for paths.
.match_paths()
// Use our custom renderer for a `DirEntry`
.picker(DirEntryRender);
// "argument parsing"
let root: PathBuf = match args().nth(1) {
Some(path) => path.into(),
None => ".".into(),
};
// populate from a separate thread to avoid locking the picker interface
let injector = picker.injector();
spawn(move || {
// add items to the picker from many threads in parallel
WalkBuilder::new(root).build_parallel().run(|| {
let injector = injector.clone(); // this is very cheap (`Arc::clone`)
Box::new(move |walk_res| {
if let Ok(dir) = walk_res {
injector.push(dir);
}
WalkState::Continue
})
});
});
match picker.pick()? {
// the matched `entry` is `&DirEntry`
Some(entry) => println!("{}", entry.path().display()),
None => {
eprintln!("No path selected!");
exit(1);
}
}
Ok(())
}