use std::any::TypeId; use std::fmt::Debug; use std::hash::Hash; use std::path::Path; use Default::default; use dsb::Cell; use crate::Freq; use crate::menu::{Key, back, filter, next, score}; use crate::text::TextArea; pub struct GenericMenu { pub data: T::Data, pub tedit: TextArea, pub selection: usize, pub vo: usize, } impl> Clone for GenericMenu { fn clone(&self) -> Self { Self { data: self.data.clone(), tedit: self.tedit.clone(), selection: self.selection.clone(), vo: self.vo.clone(), } } } impl> Default for GenericMenu { fn default() -> Self { Self { data: default(), tedit: default(), selection: default(), vo: default(), } } } impl> Debug for GenericMenu { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct(&format!( "GenericMenu<{}>", std::any::type_name::() )) .field("data", &self.data) .field("tedit", &self.tedit) .field("selection", &self.selection) .field("vo", &self.vo) .finish() } } pub enum CorA { Complete, Accept, } pub trait MenuData: Sized + 'static { const HEIGHT: usize = 30; type Data; type Element<'a>: Key<'a>; type E = !; fn complete_or_accept<'a>(_x: &Self::Element<'a>) -> CorA { CorA::Accept } fn map<'a>( _m: &GenericMenu, x: Self::Element<'a>, ) -> Result, Self::E> { Ok(x) } fn should_complete<'a>(_m: &GenericMenu) -> bool { true } fn hash<'b>(_x: &'b Self::Element<'_>) -> Option { None::<()> } fn hashed<'b>(x: &'b Self::Element<'_>) -> Option { Self::hash(x).map(|x| crate::hash(&x)) } fn gn<'a>( x: &'a Self::Data, ) -> impl Iterator>; fn r( data: &'_ Self::Data, elem: Self::Element<'_>, workspace: &Path, columns: usize, selected: bool, indices: &[u32], to: &mut Vec, ); fn filter_c<'a>( x: &'a Self::Data, f: &str, ) -> impl Iterator> { filter(Self::gn(x), f) } fn score_c<'a>( x: impl Iterator>, f: &str, freq: Option<&Freq>, ) -> Vec<(u32, Self::Element<'a>, Vec)> { score::<_, Self>(x, f, freq) } fn f(m: &GenericMenu) -> String { m.tedit.rope.to_string() } } impl GenericMenu { pub type I = T; pub fn should_render(&self) -> bool { T::should_complete(self) } // pub fn valid(&self) -> Result<(), Cow<'static, str>> { // T::valid(self) // } pub fn f(&self) -> String { T::f(self) } pub fn next(&mut self) where [(); T::HEIGHT]:, { let n = T::filter_c(&self.data, &self.f()).count(); // coz its bottom up back::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo); } pub fn sel( &self, fq: Option<&mut Freq>, ) -> Option::Element<'_>, T::E>> { let f = self.f(); T::score_c(T::filter_c(&self.data, &f), &f, fq.as_deref()) .try_remove(self.selection) .map(|(_, x, _)| T::map(&self, x)) .inspect(|x| { fq.map(|fq| { _ = x.as_ref().inspect(|x| { let x = T::hashed(x).expect( "if calling with freq, please impl hash", ); *fq.entry(TypeId::of::()) .or_default() .entry(x) .or_default() += 1; }); }); }) } pub fn back(&mut self) where [(); T::HEIGHT]:, { let n = T::filter_c(&self.data, &self.f()).count(); next::<{ T::HEIGHT }>(n, &mut self.selection, &mut self.vo); } pub fn cells( &self, c: usize, ws: &Path, freq: Option<&Freq>, ) -> Vec { let f = self.f(); let mut out = vec![]; let v = T::score_c(T::filter_c(&self.data, &f), &f, freq); let vlen = v.len(); let i = v.into_iter().zip(0..vlen).skip(self.vo).take(T::HEIGHT).rev(); i.for_each(|((_, x, indices), i)| { T::r( &self.data, x, ws, c, i == self.selection, &indices, &mut out, ) }); out } }