use crate::storage::Post;
use ratatui::{
DefaultTerminal, Frame,
crossterm::event::{self, Event, KeyCode},
widgets::{Block, Borders, Paragraph},
};
use std::io;
struct App<'a> {
results: Vec<String>,
selected_index: usize,
selected_value: Option<String>,
exit: bool,
needle: String,
raw_posts: &'a [&'a Post],
}
impl<'a> App<'a> {
fn new(posts: &'a [&'a Post], needle: &str) -> Self {
let max_cmd_len = posts.iter().map(|p| p.command.len()).max().unwrap_or(10);
Self {
raw_posts: posts,
results: posts
.iter()
.map(|p| {
format!(
"{:<width$} |Desc| {}",
p.command,
p.comment,
width = max_cmd_len
)
})
.collect(),
selected_index: 0,
selected_value: None,
exit: false,
needle: format!("Sorted by the distance to the search phrase:{}", needle),
}
}
pub fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<Option<String>> {
while !self.exit {
terminal.draw(|frame| self.draw(frame))?;
self.handle_events()?;
}
Ok(self.selected_value.clone())
}
fn draw(&self, frame: &mut Frame) {
let mut list_text = String::new();
for (i, item) in self.results.iter().enumerate() {
if i == self.selected_index {
list_text.push_str(&format!("> {}\n", item));
} else {
list_text.push_str(&format!(" {}\n", item));
}
}
let p = Paragraph::new(list_text).block(
Block::default()
.borders(Borders::ALL)
.title(self.needle.as_str()),
);
frame.render_widget(p, frame.area());
}
fn handle_events(&mut self) -> io::Result<()> {
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Up => {
if self.selected_index > 0 {
self.selected_index -= 1;
}
}
KeyCode::Down => {
if self.selected_index < self.results.len() - 1 {
self.selected_index += 1;
}
}
KeyCode::Enter => {
self.selected_value = Some(self.raw_posts[self.selected_index].command.clone());
self.exit = true; }
KeyCode::Esc | KeyCode::Char('q') => {
self.exit = true;
}
KeyCode::Char('k') => {
if self.selected_index > 0 {
self.selected_index -= 1;
}
}
KeyCode::Char('j') => {
if self.selected_index < self.results.len() - 1 {
self.selected_index += 1;
}
}
_ => {}
}
}
Ok(())
}
}
pub fn check(matches: &Vec<&Post>, needle: &str) -> color_eyre::Result<()> {
color_eyre::install()?;
let mut terminal = ratatui::init();
let mut app = App::new(matches, needle);
let result = app.run(&mut terminal)?;
ratatui::restore();
if let Some(selection) = result {
println!("{}", selection);
} else {
eprintln!("No item selected.");
}
Ok(())
}