entrust-dialog 0.6.0

Interactive terminal dialogs for entrust
Documentation
use crate::select::Item;
use fuzzy_matcher::FuzzyMatcher;
use fuzzy_matcher::skim::SkimMatcherV2;
use ratatui::widgets::ListState;
use std::sync::LazyLock;

static MATCHER: LazyLock<SkimMatcherV2> = LazyLock::new(SkimMatcherV2::default);

pub(super) struct FilteredItem<'a> {
    pub(super) item: &'a Item<'a>,
    pub(super) matching_chars: Vec<usize>,
}

pub(super) fn apply_filter<'a>(
    list: &'a [Item<'a>],
    list_state: &mut ListState,
    filter: &str,
) -> Vec<FilteredItem<'a>> {
    let filtered = get_filtered(list, filter);
    if filtered.is_empty() {
        list_state.select(None)
    } else if let Some(selected) = list_state.selected() {
        let clamped = selected.clamp(0, filtered.len() - 1);
        list_state.select(Some(clamped))
    } else {
        list_state.select(Some(0))
    }
    filtered
}

pub(super) fn get_filtered<'a>(list: &'a [Item<'a>], filter: &str) -> Vec<FilteredItem<'a>> {
    list.iter()
        .map(|i| FilteredItem {
            item: i,
            matching_chars: MATCHER
                .fuzzy_indices(i.content.as_ref(), filter)
                .map(|(_, i)| i)
                .unwrap_or_default(),
        })
        .filter(|i| filter.is_empty() || !i.matching_chars.is_empty())
        .collect()
}