|
| 1 | +use std::sync::Arc; |
| 2 | + |
| 3 | +use crossterm::event::KeyEventKind; |
1 | 4 | use eyre::Result; |
| 5 | +use tokio::sync::Mutex; |
2 | 6 | use tokio::sync::mpsc::unbounded_channel; |
3 | 7 | use tracing::error; |
4 | 8 |
|
| 9 | +use super::Component; |
5 | 10 | use crate::ui::action::Action; |
6 | | -use crate::ui::tui::Tui; |
| 11 | +use crate::ui::config::{ |
| 12 | + Config, |
| 13 | + Mode, |
| 14 | +}; |
| 15 | +use crate::ui::tui::{ |
| 16 | + Event, |
| 17 | + Tui, |
| 18 | +}; |
7 | 19 |
|
8 | 20 | pub struct App { |
| 21 | + pub config: Config, |
9 | 22 | pub should_quit: bool, |
| 23 | + pub components: Arc<Mutex<Vec<Box<dyn Component>>>>, |
10 | 24 | } |
11 | 25 |
|
12 | 26 | impl App { |
13 | 27 | pub async fn run(&mut self) -> Result<()> { |
14 | | - let (_render_tx, mut render_rx) = unbounded_channel::<()>(); |
15 | | - let (action_tx, mut _action_rx) = unbounded_channel::<Action>(); |
| 28 | + let (render_tx, mut render_rx) = unbounded_channel::<()>(); |
| 29 | + let (action_tx, mut action_rx) = unbounded_channel::<Action>(); |
16 | 30 |
|
17 | 31 | let mut tui = Tui::new(4.0, 60.0)?; |
18 | 32 | // TODO: make a defer routine that restores the terminal on exit |
19 | 33 | tui.enter()?; |
20 | 34 |
|
21 | 35 | let mut event_receiver = tui.event_rx.take().expect("Missing event receiver"); |
| 36 | + let components_clone = self.components.clone(); |
22 | 37 |
|
23 | 38 | // Render Task |
24 | 39 | tokio::spawn(async move { |
25 | 40 | while render_rx.recv().await.is_some() { |
26 | | - // TODO: render here |
27 | | - tui.terminal.draw(|_f| {})?; |
| 41 | + let mut components = components_clone.lock().await; |
| 42 | + tui.terminal.draw(|f| { |
| 43 | + for component in components.iter_mut() { |
| 44 | + if let Err(e) = component.draw(f, f.area()) { |
| 45 | + error!("Error rendering component {:?}", e); |
| 46 | + } |
| 47 | + } |
| 48 | + })?; |
28 | 49 | } |
29 | 50 |
|
30 | 51 | Ok::<(), Box<dyn std::error::Error + Send + Sync + 'static>>(()) |
31 | 52 | }); |
32 | 53 |
|
33 | 54 | // Event monitoring task |
| 55 | + let config = self.config.clone(); |
| 56 | + let action_tx_clone = action_tx.clone(); |
| 57 | + let components_clone = self.components.clone(); |
| 58 | + |
34 | 59 | tokio::spawn(async move { |
35 | | - while let Some(_event) = event_receiver.recv().await { |
36 | | - // TODO: derive action from the main component |
37 | | - let action = Action::Tick; |
38 | | - if let Err(e) = action_tx.send(action) { |
39 | | - error!("Error sending action: {:?}", e); |
| 60 | + let mut key_event_buf = Vec::<crossterm::event::KeyEvent>::new(); |
| 61 | + |
| 62 | + while let Some(event) = event_receiver.recv().await { |
| 63 | + let Ok(action) = handle_events(&event, &mut key_event_buf, &config) else { |
| 64 | + error!("Error covnerting tui events to action"); |
| 65 | + continue; |
| 66 | + }; |
| 67 | + |
| 68 | + tracing::info!("action: {:?}", action); |
| 69 | + |
| 70 | + match action { |
| 71 | + Some(action) => { |
| 72 | + if let Err(e) = action_tx_clone.send(action) { |
| 73 | + error!("Error sending action: {:?}", e); |
| 74 | + } |
| 75 | + }, |
| 76 | + None => { |
| 77 | + // The received input did not correspond to any actions, we'll let each |
| 78 | + // component handle the event |
| 79 | + let mut components = components_clone.lock().await; |
| 80 | + |
| 81 | + for component in components.iter_mut() { |
| 82 | + match component.handle_events(event.clone()) { |
| 83 | + Ok(action) => { |
| 84 | + if let Some(action) = action { |
| 85 | + if let Err(e) = action_tx_clone.send(action) { |
| 86 | + error!("Error sending action from component handle event: {:?}", e); |
| 87 | + } |
| 88 | + } |
| 89 | + }, |
| 90 | + Err(e) => { |
| 91 | + error!("Error handling event by component: {:?}", e); |
| 92 | + }, |
| 93 | + } |
| 94 | + } |
| 95 | + }, |
40 | 96 | } |
41 | 97 | } |
42 | 98 | }); |
43 | 99 |
|
| 100 | + // Main loop |
| 101 | + while let Some(action) = action_rx.recv().await { |
| 102 | + match action { |
| 103 | + Action::Render => { |
| 104 | + if let Err(e) = render_tx.send(()) { |
| 105 | + error!("Error sending rendering message to rendering thread: {:?}", e); |
| 106 | + } |
| 107 | + }, |
| 108 | + Action::Tick => {}, |
| 109 | + Action::Resize(_, _) => {}, |
| 110 | + Action::Quit => {}, |
| 111 | + Action::ClearScreen => {}, |
| 112 | + Action::Error(_) => {}, |
| 113 | + Action::Help => {}, |
| 114 | + } |
| 115 | + |
| 116 | + let mut components = self.components.lock().await; |
| 117 | + for component in components.iter_mut() { |
| 118 | + match component.update(action.clone()) { |
| 119 | + Ok(subsequent_action) => { |
| 120 | + if let Some(subsequent_action) = subsequent_action { |
| 121 | + if let Err(e) = action_tx.send(subsequent_action) { |
| 122 | + error!("Error sending subsequent action: {:?}", e); |
| 123 | + } |
| 124 | + } |
| 125 | + }, |
| 126 | + Err(e) => error!("Error updating component: {:?}", e), |
| 127 | + } |
| 128 | + } |
| 129 | + } |
| 130 | + |
44 | 131 | Ok(()) |
45 | 132 | } |
46 | 133 | } |
| 134 | + |
| 135 | +fn handle_events( |
| 136 | + event: &Event, |
| 137 | + key_event_buf: &mut Vec<crossterm::event::KeyEvent>, |
| 138 | + config: &Config, |
| 139 | +) -> Result<Option<Action>> { |
| 140 | + match event { |
| 141 | + Event::Quit => Ok(Some(Action::Quit)), |
| 142 | + Event::Tick => Ok(Some(Action::Tick)), |
| 143 | + Event::Render => Ok(Some(Action::Render)), |
| 144 | + Event::Resize(x, y) => Ok(Some(Action::Resize(*x, *y))), |
| 145 | + Event::Key(key) => { |
| 146 | + match key.kind { |
| 147 | + KeyEventKind::Release => { |
| 148 | + let mut idx = None::<usize>; |
| 149 | + for (i, event) in key_event_buf.iter().enumerate() { |
| 150 | + if event.code == key.code { |
| 151 | + idx.replace(i); |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + if let Some(idx) = idx { |
| 156 | + key_event_buf.remove(idx); |
| 157 | + } |
| 158 | + |
| 159 | + Ok(Some(Action::Tick)) |
| 160 | + }, |
| 161 | + KeyEventKind::Press => { |
| 162 | + let Some(keybindings) = &config.keybindings.0.get(&Mode::default()) else { |
| 163 | + return Ok(None); |
| 164 | + }; |
| 165 | + |
| 166 | + match keybindings.get(&vec![*key]) { |
| 167 | + Some(action) => Ok(Some(action.clone())), |
| 168 | + _ => { |
| 169 | + // If the key was not handled as a single key action, |
| 170 | + // then consider it for multi-key combinations. |
| 171 | + key_event_buf.push(*key); |
| 172 | + |
| 173 | + // Check for multi-key combinations |
| 174 | + Ok(keybindings.get(key_event_buf).cloned()) |
| 175 | + }, |
| 176 | + } |
| 177 | + }, |
| 178 | + _ | KeyEventKind::Repeat => Ok(None), |
| 179 | + } |
| 180 | + }, |
| 181 | + _ => Err(eyre::eyre!("Event not yet supported")), |
| 182 | + } |
| 183 | +} |
0 commit comments