use std::iter::{Chain, Skip, Take};
use std::slice::Iter;
use ratatui::style::Style;
pub trait Selectable {
fn is_empty(&self) -> bool;
fn len(&self) -> usize;
fn next(&mut self);
fn prev(&mut self);
fn index(&self) -> usize;
fn set_index(&mut self, index: usize);
fn selected_is_last(&self) -> bool;
}
pub trait Content<T>: Selectable {
fn selected(&self) -> Option<&T>;
fn content(&self) -> &Vec<T>;
fn push(&mut self, t: T);
fn style(&self, index: usize, style: &Style) -> Style;
}
pub trait ToPath {
fn to_path(&self) -> &std::path::Path;
}
pub trait IndexToIndex<T> {
fn index_to_index(&self) -> Chain<Skip<Iter<'_, T>>, Take<Iter<'_, T>>>;
}
#[macro_export]
macro_rules! impl_selectable {
($struct:ident) => {
use $crate::modes::Selectable;
impl Selectable for $struct {
fn is_empty(&self) -> bool {
self.content.is_empty()
}
fn len(&self) -> usize {
self.content.len()
}
fn prev(&mut self) {
if self.is_empty() {
self.index = 0
} else if self.index > 0 {
self.index -= 1;
} else {
self.index = self.len() - 1
}
}
fn next(&mut self) {
if self.is_empty() {
self.index = 0;
} else {
self.index = (self.index + 1) % self.len()
}
}
fn index(&self) -> usize {
self.index
}
fn set_index(&mut self, index: usize) {
if index < self.len() {
self.index = index;
}
}
fn selected_is_last(&self) -> bool {
return self.index() + 1 == self.len();
}
}
};
}
#[macro_export]
macro_rules! impl_index_to_index {
($content_type:ident, $struct:ident) => {
use std::iter::{Chain, Enumerate, Skip, Take};
use std::slice::Iter;
use $crate::modes::IndexToIndex;
impl IndexToIndex<$content_type> for $struct {
fn index_to_index(
&self,
) -> Chain<Skip<Iter<'_, $content_type>>, Take<Iter<'_, $content_type>>> {
let index = self.index;
let elems = self.content();
elems.iter().skip(index + 1).chain(elems.iter().take(index))
}
}
};
}
#[macro_export]
macro_rules! impl_content {
($struct:ident, $content_type:ident) => {
impl_selectable!($struct);
use $crate::modes::Content;
impl Content<$content_type> for $struct {
fn selected(&self) -> Option<&$content_type> {
match self.is_empty() {
true => None,
false => Some(&self.content[self.index]),
}
}
fn content(&self) -> &Vec<$content_type> {
&self.content
}
fn style(&self, index: usize, style: &ratatui::style::Style) -> ratatui::style::Style {
let mut style = *style;
if index == self.index() {
style.add_modifier |= ratatui::style::Modifier::REVERSED;
}
style
}
fn push(&mut self, element: $content_type) {
self.content.push(element)
}
}
};
}