use std::sync::Arc;
use nucleo::{Config, Nucleo, Utf32String};
use super::*;
use crate::render::StrRenderer;
use Action::*;
enum Action<'a> {
Incr(u32),
Decr(u32),
Reset,
Update(&'a [&'static str]),
Resize(u16),
}
fn reset(nc: &mut Nucleo<&'static str>, items: &[&'static str]) {
nc.restart(true);
let injector = nc.injector();
for item in items {
injector.push(item, |item, cols| {
cols[0] = Utf32String::from(*item);
});
}
while nc.tick(5).running {}
}
struct MatchListTester {
match_list: MatchList<&'static str, StrRenderer>,
}
#[derive(Debug, Clone, PartialEq)]
struct LayoutView<'a> {
pub below: &'a [usize],
pub above: &'a [usize],
}
impl MatchListTester {
fn init_inner(size: u16, max_padding: u16, reversed: bool) -> Self {
let mut nc = Nucleo::new(Config::DEFAULT, Arc::new(|| {}), Some(1), 1);
nc.sort_results(false);
let mut mc = MatchListConfig::default();
mc.scroll_padding = max_padding;
mc.reversed = reversed;
let mut match_list = MatchList::new(mc, Config::DEFAULT, nc, StrRenderer.into());
match_list.resize(size);
Self { match_list }
}
fn init(size: u16, max_padding: u16) -> Self {
Self::init_inner(size, max_padding, false)
}
fn init_rev(size: u16, max_padding: u16) -> Self {
Self::init_inner(size, max_padding, true)
}
fn update(&mut self, lc: Action) {
match lc {
Action::Incr(incr) => {
self.match_list.selection_incr(incr);
}
Action::Decr(decr) => {
self.match_list.selection_decr(decr);
}
Action::Reset => {
self.match_list.reset();
}
Action::Update(items) => {
reset(&mut self.match_list.nucleo, items);
self.match_list.update_items();
}
Action::Resize(sz) => {
self.match_list.resize(sz);
}
}
}
fn view(&self) -> LayoutView<'_> {
LayoutView {
above: &self.match_list.above,
below: &self.match_list.below,
}
}
#[allow(unused)]
fn debug_items(&self) {
for item in self.match_list.nucleo.snapshot().matched_items(..).rev() {
println!("* * * * * *\n{}", item.data);
}
}
#[allow(unused)]
fn debug_items_rev(&self) {
for item in self.match_list.nucleo.snapshot().matched_items(..) {
println!("* * * * * *\n{}", item.data);
}
}
}
macro_rules! assert_layout {
($lt:ident, $op:expr_2021, $below:expr_2021, $above:expr_2021) => {
$lt.update($op);
assert_eq!(
$lt.view(),
LayoutView {
below: $below,
above: $above
}
);
};
}
#[test]
fn basic() {
let mut lt = MatchListTester::init(6, 2);
assert_layout!(lt, Update(&["12\n34", "ab"]), &[2], &[1]);
assert_layout!(lt, Incr(1), &[1, 2], &[]);
assert_layout!(lt, Reset, &[2], &[1]);
assert_layout!(lt, Incr(1), &[1, 2], &[]);
assert_layout!(lt, Incr(1), &[1, 2], &[]);
let mut lt = MatchListTester::init_rev(6, 2);
assert_layout!(lt, Update(&["12\n34", "ab"]), &[2, 1], &[]);
assert_layout!(lt, Incr(1), &[1], &[2]);
assert_layout!(lt, Reset, &[2, 1], &[]);
assert_layout!(lt, Incr(1), &[1], &[2]);
assert_layout!(lt, Incr(1), &[1], &[2]);
}
#[test]
fn size_and_item_edge_cases() {
let mut lt = MatchListTester::init(6, 2);
assert_layout!(lt, Incr(1), &[], &[]);
assert_layout!(lt, Decr(1), &[], &[]);
assert_layout!(lt, Update(&[]), &[], &[]);
assert_layout!(lt, Resize(0), &[], &[]);
assert_layout!(lt, Resize(1), &[], &[]);
assert_layout!(lt, Update(&["a"]), &[1], &[]);
assert_layout!(lt, Resize(0), &[], &[]);
let mut lt = MatchListTester::init_rev(6, 2);
assert_layout!(lt, Incr(1), &[], &[]);
assert_layout!(lt, Decr(1), &[], &[]);
assert_layout!(lt, Update(&[]), &[], &[]);
assert_layout!(lt, Resize(0), &[], &[]);
assert_layout!(lt, Resize(1), &[], &[]);
assert_layout!(lt, Update(&["a"]), &[1], &[]);
assert_layout!(lt, Resize(0), &[], &[]);
}
#[test]
fn small() {
let mut lt = MatchListTester::init(5, 1);
assert_layout!(lt, Update(&["12", "a\nb"]), &[1], &[2]);
assert_layout!(lt, Incr(1), &[2, 1], &[]);
assert_layout!(lt, Decr(1), &[1], &[2]);
let mut lt = MatchListTester::init_rev(5, 1);
assert_layout!(lt, Update(&["12", "a\nb"]), &[1, 2], &[]);
assert_layout!(lt, Incr(1), &[2], &[1]);
assert_layout!(lt, Decr(1), &[1, 2], &[]);
}
#[test]
fn item_change() {
let mut lt = MatchListTester::init(4, 1);
assert_layout!(
lt,
Update(&["0\n1\n2\n3\n4\n5", "0\n1", "0\n1", "0\n1\n2\n3"]),
&[3],
&[1]
);
assert_layout!(lt, Incr(1), &[2, 1], &[1]);
assert_layout!(lt, Update(&["0\n0", "1"]), &[1, 2], &[]);
assert_layout!(lt, Update(&["0\n0", "1\n1"]), &[2, 1], &[]);
assert_layout!(lt, Update(&["0"]), &[1], &[]);
assert_layout!(lt, Update(&["0\n0\n0\n0", "1", "2", "3"]), &[3], &[1]);
assert_layout!(lt, Incr(1), &[1, 2], &[1]);
assert_layout!(lt, Update(&["0", "1", "2", "3"]), &[1, 1], &[1, 1]);
assert_layout!(lt, Update(&[]), &[], &[]);
let mut lt = MatchListTester::init_rev(4, 1);
assert_layout!(
lt,
Update(&["0\n1\n2\n3\n4\n5", "0\n1", "0\n1", "0\n1\n2\n3"]),
&[4],
&[]
);
assert_layout!(lt, Incr(1), &[2], &[2]);
assert_layout!(lt, Update(&["0\n0", "1"]), &[1], &[2]);
assert_layout!(lt, Update(&["0\n0", "1\n1"]), &[2], &[2]);
assert_layout!(lt, Update(&["0"]), &[1], &[]);
assert_layout!(lt, Update(&["0\n0\n0\n0", "1", "2", "3"]), &[4], &[]);
assert_layout!(lt, Incr(1), &[1, 1], &[2]);
assert_layout!(lt, Update(&["0", "1", "2", "3"]), &[1, 1, 1], &[1]);
assert_layout!(lt, Update(&[]), &[], &[]);
}
#[test]
fn rev_incl_selection() {
let mut lt = MatchListTester::init_rev(5, 1);
assert_layout!(
lt,
Update(&["0", "1", "2", "3", "4", "5\n5\n5"]),
&[1, 1, 1, 1, 1],
&[]
);
assert_layout!(lt, Incr(4), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Incr(1), &[3], &[1, 1]);
}
#[test]
fn resize_basic() {
let mut lt = MatchListTester::init(5, 1);
assert_layout!(
lt,
Update(&["0", "1", "2", "3", "4", "5"]),
&[1],
&[1, 1, 1, 1]
);
assert_layout!(lt, Incr(5), &[1, 1, 1, 1], &[]);
assert_layout!(lt, Resize(3), &[1, 1], &[]);
assert_layout!(lt, Resize(5), &[1, 1, 1, 1], &[]);
let mut lt = MatchListTester::init_rev(5, 1);
assert_layout!(
lt,
Update(&["0", "1", "2", "3", "4", "5"]),
&[1, 1, 1, 1, 1],
&[]
);
assert_layout!(lt, Incr(5), &[1], &[1, 1, 1]);
assert_layout!(lt, Resize(3), &[1], &[1]);
}
#[test]
fn resize_with_padding_change() {
let mut lt = MatchListTester::init(10, 2);
assert_layout!(
lt,
Update(&["0\n0\n0", "1", "2\n2", "3\n3\n3\n3"]),
&[3],
&[1, 2, 4]
);
assert_layout!(lt, Resize(4), &[3], &[1]);
assert_layout!(lt, Incr(2), &[2, 1], &[1]);
assert_layout!(lt, Resize(8), &[2, 1, 3], &[2]);
assert_layout!(lt, Resize(4), &[2, 1], &[1]);
let mut lt = MatchListTester::init_rev(10, 2);
assert_layout!(
lt,
Update(&["0\n0\n0", "1", "2\n2", "3\n3\n3\n3"]),
&[3, 1, 2, 4],
&[]
);
assert_layout!(lt, Resize(4), &[3, 1], &[]);
assert_layout!(lt, Incr(2), &[2], &[1, 1]);
assert_layout!(lt, Resize(8), &[2, 2], &[1, 3]);
assert_layout!(lt, Resize(4), &[2], &[1, 1]);
}
#[test]
fn item_alignment() {
let mut lt = MatchListTester::init(20, 3);
assert_layout!(lt, Update(&["0\n1\n2\n", "0\n1", "0\n1"]), &[4], &[2, 2]);
assert_layout!(lt, Incr(2), &[2, 2, 4], &[]);
assert_layout!(lt, Decr(1), &[2, 4], &[2]);
let mut lt = MatchListTester::init_rev(20, 3);
assert_layout!(lt, Update(&["0\n1\n2\n", "0\n1", "0\n1"]), &[4, 2, 2], &[]);
assert_layout!(lt, Incr(2), &[2], &[2, 4]);
assert_layout!(lt, Decr(1), &[2, 2], &[4]);
}
#[test]
fn scrolldown() {
let mut lt = MatchListTester::init(8, 2);
assert_layout!(
lt,
Update(&["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]),
&[1],
&[1, 1, 1, 1, 1, 1, 1]
);
assert_layout!(lt, Incr(100), &[1, 1, 1, 1, 1, 1], &[]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1, 1], &[1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1], &[1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1], &[1, 1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1], &[1, 1, 1, 1, 1]);
assert_layout!(lt, Decr(3), &[1, 1, 1], &[1, 1, 1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1], &[1, 1, 1, 1, 1, 1]);
assert_layout!(lt, Decr(1), &[1], &[1, 1, 1, 1, 1, 1, 1]);
assert_layout!(lt, Decr(1), &[1], &[1, 1, 1, 1, 1, 1, 1]);
let mut lt = MatchListTester::init_rev(8, 2);
assert_layout!(
lt,
Update(&["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]),
&[1, 1, 1, 1, 1, 1, 1, 1],
&[]
);
assert_layout!(lt, Incr(100), &[1], &[1, 1, 1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1], &[1, 1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1], &[1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(3), &[1, 1, 1, 1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1, 1, 1, 1], &[1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1, 1, 1, 1, 1], &[]);
}
#[test]
fn scrollback() {
let mut lt = MatchListTester::init(5, 1);
assert_layout!(
lt,
Update(&["12\n34", "ab", "c", "d", "e", "f\ng"]),
&[2],
&[1, 1, 1]
);
assert_layout!(lt, Incr(3), &[1, 1, 1, 1], &[1]);
assert_layout!(lt, Incr(1), &[1, 1, 1, 1], &[1]);
assert_layout!(lt, Incr(1), &[2, 1, 1], &[]);
assert_layout!(lt, Decr(1), &[1, 1], &[2]);
assert_layout!(lt, Incr(1), &[2, 1, 1], &[]);
assert_layout!(lt, Decr(2), &[1, 1], &[1, 2]);
assert_layout!(lt, Decr(1), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Decr(1), &[2], &[1, 1, 1]);
let mut lt = MatchListTester::init_rev(5, 1);
assert_layout!(
lt,
Update(&["12\n34", "ab", "c", "d", "e", "f\ng"]),
&[2, 1, 1, 1],
&[]
);
assert_layout!(lt, Incr(3), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Incr(1), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Incr(1), &[2], &[1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 2], &[1, 1]);
assert_layout!(lt, Incr(1), &[2], &[1, 1, 1]);
assert_layout!(lt, Decr(2), &[1, 1, 2], &[1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1], &[1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1], &[1]);
assert_layout!(lt, Decr(1), &[2, 1, 1, 1], &[]);
}
#[test]
fn multiline_jitter() {
let mut lt = MatchListTester::init(12, 3);
assert_layout!(
lt,
Update(&["a", "b", "0\n1\n2\n3", "0\n1", "0\n1"]),
&[1],
&[1, 4, 2, 2]
);
assert_layout!(lt, Incr(1), &[1, 1], &[4, 2, 2]);
assert_layout!(lt, Incr(1), &[4, 1, 1], &[2, 2]);
assert_layout!(lt, Incr(1), &[2, 4, 1, 1], &[2]);
assert_layout!(lt, Incr(1), &[2, 2, 4, 1], &[]);
assert_layout!(lt, Decr(1), &[2, 4, 1], &[2]);
assert_layout!(lt, Decr(1), &[4, 1], &[2, 2]);
assert_layout!(lt, Incr(1), &[2, 4, 1], &[2]);
let mut lt = MatchListTester::init_rev(10, 3);
assert_layout!(
lt,
Update(&["a", "b", "0\n1\n2\n3", "0\n1", "0\n1"]),
&[1, 1, 4, 2, 2],
&[]
);
assert_layout!(lt, Incr(1), &[1, 4, 2, 2], &[1]);
assert_layout!(lt, Incr(1), &[4, 2, 2], &[1, 1]);
assert_layout!(lt, Incr(1), &[2, 2], &[4, 1, 1]);
assert_layout!(lt, Incr(1), &[2], &[2, 4]);
assert_layout!(lt, Decr(1), &[2, 2], &[4]);
assert_layout!(lt, Decr(1), &[4, 2, 2], &[1, 1]);
assert_layout!(lt, Incr(1), &[2, 2], &[4, 1, 1]);
}
#[test]
fn scroll_mid() {
let mut lt = MatchListTester::init(5, 1);
assert_layout!(
lt,
Update(&["0", "1", "2", "3", "4", "5", "6", "7"]),
&[1],
&[1, 1, 1, 1]
);
assert_layout!(lt, Incr(4), &[1, 1, 1, 1], &[1]);
assert_layout!(lt, Decr(2), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Incr(1), &[1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(1), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Resize(7), &[1, 1, 1], &[1, 1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1], &[1, 1, 1, 1, 1]);
assert_layout!(lt, Incr(2), &[1, 1, 1, 1], &[1, 1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1], &[1, 1, 1, 1]);
assert_layout!(lt, Incr(1), &[1, 1, 1, 1], &[1, 1, 1]);
assert_layout!(lt, Decr(2), &[1, 1], &[1, 1, 1, 1, 1]);
assert_layout!(lt, Incr(20), &[1, 1, 1, 1, 1, 1], &[]);
let mut lt = MatchListTester::init_rev(5, 1);
assert_layout!(
lt,
Update(&["0", "1", "2", "3", "4", "5", "6", "7"]),
&[1, 1, 1, 1, 1],
&[]
);
assert_layout!(lt, Incr(4), &[1, 1], &[1, 1, 1]);
assert_layout!(lt, Decr(2), &[1, 1, 1, 1], &[1]);
assert_layout!(lt, Incr(1), &[1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1], &[1]);
assert_layout!(lt, Resize(7), &[1, 1, 1, 1, 1], &[1, 1]);
assert_layout!(lt, Decr(1), &[1, 1, 1, 1, 1, 1], &[1]);
}