use memchr::memchr_iter;
use nucleo::{Item, Snapshot, Utf32Str};
use super::{ItemList, ItemSize};
use crate::Render;
impl<T> ItemSize for Item<'_, T> {
fn size(&self) -> usize {
let num_linebreaks = match self.matcher_columns[0].slice(..) {
Utf32Str::Ascii(bytes) => memchr_iter(b'\n', bytes).count(),
Utf32Str::Unicode(chars) => {
chars
.iter()
.filter(|ch| **ch == '\n' || **ch == '\r')
.count()
}
};
1 + num_linebreaks
}
}
impl<T: Send + Sync + 'static> ItemList for Snapshot<T> {
type Item<'a>
= Item<'a, T>
where
Self: 'a;
fn total(&self) -> u32 {
self.matched_item_count()
}
fn lower(&self, selection: u32) -> impl DoubleEndedIterator<Item = Self::Item<'_>> {
self.matched_items(..selection).rev()
}
fn lower_inclusive(&self, selection: u32) -> impl DoubleEndedIterator<Item = Self::Item<'_>> {
self.matched_items(..=selection).rev()
}
fn higher(&self, selection: u32) -> impl DoubleEndedIterator<Item = Self::Item<'_>> {
self.matched_items(selection..).skip(1)
}
fn higher_inclusive(&self, selection: u32) -> impl DoubleEndedIterator<Item = Self::Item<'_>> {
self.matched_items(selection..)
}
}
pub enum RenderedItem<'a, S> {
Ascii(&'a str),
Unicode(S),
}
impl<'a, S> RenderedItem<'a, S> {
pub fn new<T, R>(item: &Item<'a, T>, renderer: &R) -> Self
where
R: Render<T, Str<'a> = S>,
{
if let Utf32Str::Ascii(bytes) = item.matcher_columns[0].slice(..) {
RenderedItem::Ascii(unsafe { std::str::from_utf8_unchecked(bytes) })
} else {
RenderedItem::Unicode(renderer.render(item.data))
}
}
}
impl<S: AsRef<str>> AsRef<str> for RenderedItem<'_, S> {
fn as_ref(&self) -> &str {
match self {
RenderedItem::Ascii(s) => s,
RenderedItem::Unicode(u) => u.as_ref(),
}
}
}