zdir 0.1.1

A blazingly-faster cd alternative
use ratatui::{
    DefaultTerminal, Frame, TerminalOptions, Viewport,
    crossterm::event::{self, Event, KeyCode, KeyEventKind},
    style::{Color, Style},
    text::{Line, Span},
    widgets::{Block, BorderType, Borders, List, ListItem, ListState},
};
use std::process;

struct App {
    state: ListState,
    results: Vec<(f64, String)>,
    running: bool,
}

impl App {
    pub fn new(results: Vec<(f64, String)>) -> Self {
        let mut list_state = ListState::default();
        list_state.select(Some(0));
        Self {
            state: list_state,
            results,
            running: true,
        }
    }

    pub fn run(&mut self, terminal: &mut DefaultTerminal) -> String {
        let mut selected: String = String::new();

        while self.running {
            terminal.draw(|frame| self.render(frame)).unwrap();
            selected = self.keybinds();
        }

        selected
    }

    fn render(&mut self, frame: &mut Frame) {
        let list = List::new(
            self.results
                .iter()
                .map(|(s, p)| {
                    ListItem::new(Line::from(vec![
                        Span::styled(
                            s.to_string(),
                            Style::default().fg(Color::Green),
                        ),
                        Span::raw(" "),
                        Span::raw(p),
                    ]))
                })
                .collect::<Vec<ListItem>>(),
        )
        .block(
            Block::default()
                .title(" Select a directory ")
                .borders(Borders::ALL)
                .border_style(Style::new().fg(Color::Rgb(203, 166, 247)))
                .border_type(BorderType::Rounded),
        )
        .highlight_symbol("")
        .highlight_style(Style::new().fg(Color::Rgb(203, 166, 247)));

        frame.render_stateful_widget(list, frame.area(), &mut self.state);
    }

    fn keybinds(&mut self) -> String {
        match event::read().unwrap() {
            Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
                match key_event.code {
                    KeyCode::Esc => process::exit(-1),
                    KeyCode::Up => {
                        self.state.select_previous();
                        "".to_string()
                    }
                    KeyCode::Down => {
                        self.state.select_next();
                        "".to_string()
                    }
                    KeyCode::Enter => {
                        if let Some(i) = self.state.selected()
                            && let Some((_, selection)) = self.results.get(i)
                        {
                            self.running = false;
                            selection.to_string()
                        } else {
                            "".to_string()
                        }
                    }
                    _ => "".to_string(),
                }
            }
            _ => "".to_string(),
        }
    }
}

pub fn tui(results: Vec<(f64, String)>) -> String {
    let mut terminal = ratatui::init_with_options(TerminalOptions {
        viewport: Viewport::Inline(10),
    });

    App::new(results).run(&mut terminal)
}