cargo_function_history/
lib.rs

1use std::{cell::RefCell, io::stdout, process::exit, rc::Rc, time::Duration};
2
3use crate::app::ui;
4use app::{state::AppState, App, AppReturn};
5use crossterm::event::{self, Event, KeyCode};
6use eyre::Result;
7use keys::Key;
8use tui::{backend::CrosstermBackend, Terminal};
9use tui_input::backend::crossterm as input_backend;
10
11pub mod app;
12pub mod keys;
13pub fn start_ui(app: Rc<RefCell<App>>) -> Result<()> {
14    // Configure Crossterm backend for tui
15    let stdout = stdout();
16    crossterm::terminal::enable_raw_mode()?;
17    let backend = CrosstermBackend::new(stdout);
18    let mut terminal = Terminal::new(backend)?;
19    terminal.clear()?;
20    terminal.hide_cursor()?;
21    let mut x = false;
22    loop {
23        let mut app = app.borrow_mut();
24
25        // Render
26        terminal.draw(|rect| {
27            // check if we have enough space to draw
28            if rect.size().width < 15 || rect.size().height < 15 {
29                x = true
30            } else {
31                ui::draw(rect, &mut app)
32            }
33        })?;
34
35        if x {
36            break;
37        }
38        // Handle inputs
39        if let Ok(true) = event::poll(Duration::from_millis(100)) {
40            if let Event::Key(key) = event::read()? {
41                match &mut app.state() {
42                    AppState::Editing => match key.code {
43                        KeyCode::Enter => {
44                            app.run_command();
45                            app.history_index = app.history.len();
46                            app.reset_and_save()
47                        }
48                        KeyCode::Esc => {
49                            app.state = AppState::Looking;
50                        }
51                        KeyCode::Delete => app.input_buffer.reset(),
52                        KeyCode::Up => {
53                            app.reset_and_save();
54                            app.scroll_up();
55                        }
56                        KeyCode::Down => {
57                            app.reset_and_save();
58                            app.scroll_down();
59                        }
60                        _ => {
61                            input_backend::to_input_request(Event::Key(key))
62                                .and_then(|req| app.input_buffer.handle(req));
63                        }
64                    },
65                    _ => {
66                        let result = app.do_action(Key::from(key));
67                        // Check if we should exit
68                        if result == AppReturn::Exit {
69                            break;
70                        }
71                    }
72                }
73            }
74        }
75    }
76
77    // Restore the terminal and close application
78    terminal.clear()?;
79    terminal.show_cursor()?;
80    crossterm::terminal::disable_raw_mode()?;
81    if x {
82        eprintln!("Not enough space to draw");
83        exit(1)
84    }
85
86    Ok(())
87}