use std::{env, fs, io, path::PathBuf}; use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind}; use ratatui::{ DefaultTerminal, Frame, buffer::Buffer, layout::Rect, style::{Color, Stylize}, widgets::{Block, Borders, List, ListState, Padding, StatefulWidget}, }; struct App<'a> { window: Window<'a>, exit: bool, } impl App<'_> { fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> { while !self.exit { terminal.draw(|frame| self.draw(frame))?; self.handle_events()?; } Ok(()) } fn draw(&mut self, frame: &mut Frame) { self.window.render(frame.area(), frame.buffer_mut()); } fn handle_events(&mut self) -> io::Result<()> { match event::read()? { Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { self.handle_key_events(key_event) } _ => {} }; Ok(()) } fn handle_key_events(&mut self, key_event: KeyEvent) { match key_event.code { KeyCode::Char('q') | KeyCode::Esc => self.exit(), KeyCode::Down => self.window.state.select_next(), KeyCode::Up => self.window.state.select_previous(), KeyCode::Left => { self.window.absolute_path.pop(); self.window.update(); } KeyCode::Right => match self.window.state.selected() { Some(val) => { self.window .absolute_path .push(self.window.prepare_updated_list()[val].clone()); self.window.update(); } None => { print!("hello"); } }, _ => {} } } fn exit(&mut self) { self.exit = true; } } struct Window<'a> { widget: WindowWidget<'a>, absolute_path: PathBuf, state: ListState, } impl Window<'_> { fn new(absolute_path: PathBuf) -> Self { Window { widget: WindowWidget::new(Self::prepare_list(&absolute_path)), absolute_path, state: ListState::default().with_selected(Some(0)), } } fn render(&mut self, area: Rect, buf: &mut Buffer) { self.widget.render(area, buf, &mut self.state); } fn prepare_list(absolute_path: &PathBuf) -> Vec { match fs::read_dir(absolute_path) { Ok(val) => { let mut the_list: Vec = Vec::new(); for item in val { the_list.push(item.unwrap().path().display().to_string()); } return the_list; } Err(err) => {} } } fn prepare_updated_list(&self) -> Vec { Self::prepare_list(&self.absolute_path) } fn update(&mut self) { self.widget.update(self.prepare_updated_list()); } } struct WindowWidget<'a> { list: List<'a>, } impl WindowWidget<'_> { fn update(&mut self, prepared_list: Vec) { let block = Block::new() .borders(Borders::ALL) .padding(Padding::symmetric(1, 1)) .fg(Color::Blue); self.list = List::new(prepared_list) .block(block) .highlight_style(Color::Cyan); } fn new(prepared_list: Vec) -> Self { let mut window_widget = WindowWidget { list: List::new(Vec::::new()), }; window_widget.update(prepared_list); window_widget } } impl StatefulWidget for &mut WindowWidget<'_> { type State = ListState; fn render(self, area: Rect, buf: &mut Buffer, state: &mut ListState) { StatefulWidget::render(&self.list, area, buf, state); } } fn main() -> io::Result<()> { let mut terminal = ratatui::init(); let dir = Window::new(env::current_dir().unwrap()); let app_result = App { window: dir, exit: false, } .run(&mut terminal); ratatui::restore(); app_result }