Skip to main content

Picker

Struct Picker 

Source
pub struct Picker<T: Send + Sync + 'static, R> { /* private fields */ }
Expand description

A fuzzy matching interactive item picker.

The parameter T is the item type and the parameter R is the renderer, which describes how to represent T in the match list.

Initialize a picker with Picker::new, or with custom configuration using PickerOptions, and add elements to the picker using an Injector returned by the Picker::injector method.

use nucleo_picker::{render::StrRenderer, Picker};

// Initialize a picker using default settings, with item type `String`
let picker: Picker<String, _> = Picker::new(StrRenderer);

See also the usage examples.

§Picker variants

The picker can be run in a number of different modes.

  1. The simplest (and most common) method is to use Picker::pick.
  2. If you wish to customize keybindings, use Picker::pick_with_keybind.
  3. If you wish to customize all IO to the picker, use Picker::pick_with_io.

These methods return Option<&T> as the return type, where None indicates that no items were selected.

§Multiple selections

If you wish to permit the user to make multiple selections, use one of the similarly named methods:

  1. Picker::pick_multi
  2. Picker::pick_multi_with_keybind
  3. Picker::pick_multi_with_io

These methods are analogous to their single-selection variants, except additional items can be queued with the MatchListEvent::ToggleDown and MatchListEvent::ToggleUp events. The default keybindings bind these to and shift + ⇥ respectively. In this case, an Event::Select is handled slightly differently: if there are no queued selections, this picks the highlighted item, but if there are queued selections, then only the queued selections are returned.

If the picker restarts while running, the queued item list will be cleared since the previous items are removed.

The selected items are returned as a Selection, which is empty if picker exited with Event::Quit (or Event::QuitPromptEmpty), and non-empty if not.

§Emulate single selection using a multi-picker

It is possible to emulate single selection with one of the multi-picker methods by setting PickerOptions::max_selection_count to Some(1). This will force the resulting Selection to contain either 0 or 1 element, and you can convert to Option<&T> by calling next on the iterator.

Note that the picker interface will be slightly different: it is still possible to queue at most one picked item using . With the non-multi-pickers, it is not possible to queue items at all.

§A note on memory usage

Initializing a picker is a relatively expensive operation since the internal match engine uses an arena-based memory approach to minimize allocator costs, and this memory is initialized when the picker is created.

To re-use the picker without additional start-up costs, use Picker::restart.

§Example

Run the picker on Stdout with no interactivity checks, and quitting gracefully on ctrl + c.

use std::io;

use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use nucleo_picker::{
    Picker,
    event::{Event, StdinReader, keybind_default},
    render::StrRenderer,
};

/// Keybindings which use the default keybindings, but instead of aborting on `ctrl + c`,
/// simply perform a normal quit action.
fn keybind_no_interrupt(key_event: KeyEvent) -> Option<Event> {
    match key_event {
        KeyEvent {
            kind: KeyEventKind::Press,
            modifiers: KeyModifiers::CONTROL,
            code: KeyCode::Char('c'),
            ..
        } => Some(Event::Quit),
        e => keybind_default(e),
    }
}

fn main() -> io::Result<()> {
    let mut picker = Picker::new(StrRenderer);

    let choices = vec![
        "Alvar Aalto",
        "Frank Lloyd Wright",
        "Zaha Hadid",
        "Le Corbusier",
    ];

    // populate the matcher using the convenience 'extend' implementation
    picker.extend(choices);

    // launch the interactive picker with the customized keybindings, and draw the picker on
    // standard output
    match picker.pick_with_io(
        StdinReader::new(keybind_no_interrupt),
        &mut std::io::stdout(),
    )? {
        Some(opt) => println!("Your preferred architect is: '{opt}'"),
        None => println!("No architect selected!"),
    }

    Ok(())
}

Implementations§

Source§

impl<T: Send + Sync + 'static, R> Picker<T, R>

Source

pub fn new(render: R) -> Self
where R: Render<T>,

Initialize a new picker with default configuration and the provided renderer.

Source

pub fn update_query<Q: Into<String>>(&mut self, query: Q)

Update the default query string. This is mainly useful for modifying the query string before re-using the Picker.

See the PickerOptions::query method to set the query during initialization, and PromptEvent::Reset to reset the query during interactive use.

Source

pub fn query(&self) -> &str

Returns the contents of the query string internal to the picker.

If called after running Picker::pick, this will contain the contents of the query string at the moment that the item was selected or the picker quit.

Source

pub fn injector_observer( &mut self, with_injector: bool, ) -> Observer<Injector<T, R>>

Returns an Observer containing up-to-date Injectors for this picker.

This is the channel to which new injectors will be sent when the picker processes a restart event. Restart events are not generated by this library. You only need this channel if you generate restart events in your own code. See the Event documentation for more detail.

Calling this method will invalidate all earlier observers. If you want multiple copies of the same observer, clone your existing observer.

If with_injector is true, the channel is intialized with an injector currently valid for the picker on creation.

Source

pub fn update_config(&mut self, config: Config)

Update the internal nucleo configuration.

Source

pub fn restart(&mut self)

Restart the match engine, disconnecting all active injectors and clearing the existing search query.

All items are removed immediately. Existing injectors will continue to function but the items will no longer be received by this instance. The old items will only be dropped when all injectors are dropped.

This method is mainly useful for re-using the picker for multiple matches since the internal memory buffers are preserved. To restart the picker during interactive use, see the Event documentation or the restart example.

Source

pub fn reset_renderer(&mut self, render: R)

Restart the match engine, disconnecting all active injectors and replacing the internal renderer.

The provided Render implementation must be the same type as the one originally provided; this is most useful for stateful renderers.

See Picker::restart for more detail. Note that method does not clear the query.

Source

pub fn injector(&self) -> Injector<T, R>

Get an Injector to send items to the picker.

Source

pub fn extend_exact<I>(&self, iter: I)
where R: Render<T>, I: IntoIterator<Item = T>, <I as IntoIterator>::IntoIter: ExactSizeIterator,

A convenience method to add a batch of items directly to the picker.

The number of items in the iterator must be known exactly. This is a convenience wrapper around Injector::extend_exact.

Source

pub fn render<'a>(&self, item: &'a T) -> <R as Render<T>>::Str<'a>
where R: Render<T>,

A convenience method to obtain the rendered version of an item as it would appear in the picker.

This is the same as calling Render::render on the Render implementation internal to the picker.

Source

pub fn pick(&mut self) -> Result<Option<&T>, PickError>
where R: Render<T>,

Open the interactive picker prompt and return the picked item, if any.

§Stderr lock

The picker prompt is rendered in an alternate screen using the stderr file handle. In order to prevent screen corruption, a lock is acquired to stderr; see StderrLock for more detail.

In particular, while the picker is interactive, any other thread which attempts to write to stderr will block. Note that stdin and stdout will remain fully interactive.

§IO customization

To further customize the IO behaviour of the picker, such as to provide your own writer (for instance to write to Stdout instead) or use custom keybindings, see the pick_with_io and pick_with_keybind methods.

§Errors

Underlying IO errors from the standard library or crossterm will be propagated with the PickError::IO variant.

This method also fails with:

  1. PickError::NotInteractive if stderr is not interactive.
  2. PickError::UserInterrupted if the user presses ctrl + c.

This method will never return PickError::Disconnected.

Source

pub fn pick_multi(&mut self) -> Result<Selection<'_, T>, PickError>
where R: Render<T>,

Open the interactive picker prompt and return the picked items, if any.

This method permits the user to select multiple items, but is otherwise identical to pick. See those docs as well as the docs on multiple selections for more detail.

Source

pub fn pick_with_keybind<F>( &mut self, keybind: F, ) -> Result<Option<&T>, PickError>
where R: Render<T>, F: FnMut(KeyEvent) -> Option<Event>,

Open the interactive picker prompt and return the picked item, if any. The provided keybindings are used in the interactive picker.

The picker prompt is rendered in an alternate screen using the stderr file handle. See the pick method for more detail.

To further customize event generation, see the pick_with_io method. The pick method is internally a call to this method with keybindings provided by keybind_default.

§Errors

Underlying IO errors from the standard library or crossterm will be propagated with the PickError::IO variant.

This method also fails with:

  1. PickError::NotInteractive if stderr is not interactive.
  2. PickError::UserInterrupted if a keybinding results in a Event::UserInterrupt,

This method will never return PickError::Disconnected.

Source

pub fn pick_multi_with_keybind<F>( &mut self, keybind: F, ) -> Result<Selection<'_, T>, PickError>
where R: Render<T>, F: FnMut(KeyEvent) -> Option<Event>,

Open the interactive picker prompt and return the picked item, if any. The provided keybindings are used in the interactive picker.

This method permits the user to select multiple items, but is otherwise identical to pick_with_keybind. See those docs as well as the docs on multiple selections for more detail.

Source

pub fn pick_with_io<E, W>( &mut self, event_source: E, writer: &mut W, ) -> Result<Option<&T>, PickError<<E as EventSource>::AbortErr>>
where R: Render<T>, E: EventSource, W: Write,

Run the picker interactively with a custom event source and writer.

The picker is rendered using the given writer. In most situations, you want to check that the writer is interactive using, for instance, IsTerminal. The picker reads events from the EventSource to update the screen. See the docs for EventSource for more detail.

§Errors

Underlying IO errors from the standard library or crossterm will be propagated with the PickError::IO variant.

Whether or not this fails with another PickError variant depends on the EventSource implementation:

  1. If EventSource::recv_timeout fails with a RecvError::Disconnected, the error returned will be PickError::Disconnected.
  2. The error will be PickError::UserInterrupted if the Picker receives an Event::UserInterrupt.
  3. The error will be PickError::Aborted if the Picker receives an Event::Abort.

This method will never return PickError::NotInteractive since interactivity checks are not done.

Source

pub fn pick_multi_with_io<E, W>( &mut self, event_source: E, writer: &mut W, ) -> Result<Selection<'_, T>, PickError<<E as EventSource>::AbortErr>>
where R: Render<T>, E: EventSource, W: Write,

Run the picker interactively with a custom event source and writer, allowing the user to select multiple items.

This is otherwise identical to pick_with_io; see those docs as well as the docs on multiple selections for more detail.

Trait Implementations§

Source§

impl<T: Send + Sync + 'static, R: Render<T>> Extend<T> for Picker<T, R>

Source§

fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I)

Extends a collection with the contents of an iterator. Read more
Source§

fn extend_one(&mut self, item: A)

🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
Source§

fn extend_reserve(&mut self, additional: usize)

🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more

Auto Trait Implementations§

§

impl<T, R> !RefUnwindSafe for Picker<T, R>

§

impl<T, R> !UnwindSafe for Picker<T, R>

§

impl<T, R> Freeze for Picker<T, R>

§

impl<T, R> Send for Picker<T, R>
where R: Sync + Send,

§

impl<T, R> Sync for Picker<T, R>
where R: Sync + Send,

§

impl<T, R> Unpin for Picker<T, R>

§

impl<T, R> UnsafeUnpin for Picker<T, R>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.