19 releases (7 breaking)
new 0.8.0 | Jan 14, 2025 |
---|---|
0.7.0 | Jan 13, 2025 |
0.6.4 | Dec 16, 2024 |
0.5.0 | Nov 7, 2024 |
0.1.0 | Aug 20, 2024 |
#101 in Command-line interface
648 downloads per month
Used in 2 crates
220KB
4K
SLoC
nucleo-picker
A native Rust library which enables you to incorporate a highly performant and Unicode-aware fuzzy picker directly in your own terminal application.
This library provides a TUI for the nucleo
crate with an interface similar to the fzf command-line tool.
- For implementation examples, jump to the fzf example or see the
examples
directory. - For documentation of interactive usage of the picker, see the
USAGE.md
file. - For a list of recent changes, see the
CHANGELOG.md
file.
Elevator pitch
Why use this library instead of a general-purpose fuzzy-finder such as fzf
or a lower level library such as nucleo
?
- Much tighter integration between your data source and your application.
Instead of reading from a SQLite database with
sqlite3
and then parsing raw text, read directly into in-memory data structures withrusqlite
and render the in-memory objects in the picker. - Skip the subprocess overhead and improve startup time.
Instead of starting up a subprocess to call
fzf
, have the picker integrated directly into your binary. - Distinguish items from their matcher representation.
Instead of writing your data structure to a string, passing it to
fzf
, and then parsing the resulting match string back into your data structure, directly obtain the original data structure when matching is complete. - Don't spend time debugging terminal rendering edge cases.
Out-of-the-box,
nucleo-picker
handles terminal rendering subtleties such as multiline rendering, double-width Unicode, automatic overflow scrollthrough, and grapheme-aware query input so you don't have to. - Handle complex use cases using events.
nucleo-picker
exposes a fully-featured event system which can be used to drive the picker. This lets you customize keybindings, support interactive restarts, and much more by implementing theEventSource
trait. Simplified versions of such features are available in fzf but essentially require manual configuration via an embedded DSL.
Features
- Highly optimized matching.
- Robust rendering:
- Full Unicode handling with Unicode text segmentation and Unicode width.
- Match highlighting with automatic scroll-through.
- Correctly render multi-line or overflowed items, with standard and reversed item order.
- Responsive interface with batched keyboard input.
- Ergonomic API:
- Fully concurrent lock- and wait-free streaming of input items.
- Generic
Picker
for any typeT
which isSend + Sync + 'static
. - Customizable rendering of crate-local and foreign types with the
Render
trait.
- Fully configurable event system:
- Easily customizable keybindings.
- Run the picker concurrently with your application using a fully-featured event system, with optional support for complex features such as interactive restarting.
- Optional and flexible error propagation generics so your application errors can interface cleanly with the picker.
Example
Implement a heavily simplified fzf
clone in 25 lines of code.
Try it out with:
cargo build --release --example fzf
cat myfile.txt | ./target/release/examples/fzf
The code to create the binary:
use std::{
io::{self, IsTerminal},
process::exit,
thread::spawn,
};
use nucleo_picker::{render::StrRenderer, Picker};
fn main() -> io::Result<()> {
let mut picker = Picker::new(StrRenderer);
let injector = picker.injector();
spawn(move || {
let stdin = io::stdin();
if !stdin.is_terminal() {
for line in stdin.lines() {
// silently drop IO errors!
if let Ok(s) = line {
injector.push(s);
}
}
}
});
match picker.pick()? {
Some(it) => println!("{it}"),
None => exit(1),
}
Ok(())
}
Related crates
This crate mainly exists as a result of the author's annoyance with pretty much every fuzzy picker TUI in the rust ecosystem. As far as I am aware, the fully-exposed event system is unique to this crate. Beyond this, here is a brief comparison:
- skim's
Arc<dyn SkimItem>
is inconvenient for a variety of reasons.skim
also has a large number of dependencies and is designed more as a binary than a library. - fuzzypicker is based on
skim
and inheritsskim
's problems. - nucleo-ui only has a blocking API and only supports matching on
String
. It also seems to be un-maintained. - fuzzy-select only has a blocking API.
- dialoguer
FuzzySelect
only has a blocking API and only supports matching onString
. The terminal handling also has a few strange bugs.
Disclaimer
There are a currently a few known problems which have not been addressed (see the issues page on GitHub for a list). Issues and contributions are welcome!
Dependencies
~6–15MB
~212K SLoC