main.rs (2475B)
1 use crate::app::{ui, App}; 2 use crossterm::{ 3 event::{self, DisableMouseCapture, EnableMouseCapture, Event as CEvent, KeyCode}, 4 execute, 5 terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, 6 }; 7 use std::{ 8 io::{stdout, Write}, 9 sync::mpsc, 10 thread, 11 time::{Duration, Instant}, 12 }; 13 use tui::{backend::CrosstermBackend, Terminal}; 14 mod app; 15 mod tui_utils; 16 mod extra_ruma; 17 18 enum Event<I> { 19 Input(I), 20 Tick, 21 } 22 23 #[tokio::main] 24 pub async fn main() -> anyhow::Result<()>{ 25 enable_raw_mode()?; 26 27 let mut stdout = stdout(); 28 execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; 29 let backend = CrosstermBackend::new(stdout); 30 31 let mut terminal = Terminal::new(backend)?; 32 33 // Setup input handling 34 let (tx, rx) = mpsc::channel(); 35 let tick_rate = Duration::from_millis(250); 36 37 thread::spawn(move || { 38 let mut last_tick = Instant::now(); 39 loop { 40 // poll for tick rate duration, if no events, sent tick event. 41 let timeout = tick_rate 42 .checked_sub(last_tick.elapsed()) 43 .unwrap_or_else(|| Duration::from_secs(0)); 44 if event::poll(timeout).unwrap() { 45 if let CEvent::Key(key) = event::read().unwrap() { 46 tx.send(Event::Input(key)).unwrap(); 47 } 48 } 49 if last_tick.elapsed() >= tick_rate { 50 tx.send(Event::Tick).unwrap(); 51 last_tick = Instant::now(); 52 } 53 } 54 }); 55 56 let mut app = App::new("Bookmarks", true); 57 58 terminal.clear()?; 59 60 loop { 61 terminal.draw(|f| ui::draw(f, &mut app))?; 62 match rx.recv()? { 63 Event::Input(event) => match event.code { 64 KeyCode::Char('q') => { 65 disable_raw_mode()?; 66 execute!( 67 terminal.backend_mut(), 68 LeaveAlternateScreen, 69 DisableMouseCapture 70 )?; 71 terminal.show_cursor()?; 72 break; 73 } 74 KeyCode::Char(c) => app.on_key(c), 75 KeyCode::Left => app.on_left(), 76 KeyCode::Right => app.on_right(), 77 _ => {} 78 }, 79 Event::Tick => { 80 app.on_tick(); 81 } 82 } 83 if app.should_quit { 84 break; 85 } 86 } 87 88 Ok(()) 89 }