aboutsummaryrefslogtreecommitdiff
path: root/src/app/mod.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-03-30 04:12:56 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-03-30 04:12:56 +0300
commitca14500717864b1c9b1885cbbc6a451a19b9caf8 (patch)
treec45883c9633e2275136283b75ae3e41b353073da /src/app/mod.rs
parentaee654578408c7fbdb1640d2dca8eaea4ec1754e (diff)
refactor keyboard protocol parsing and forwarding
Diffstat (limited to 'src/app/mod.rs')
-rw-r--r--src/app/mod.rs60
1 files changed, 45 insertions, 15 deletions
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 15ae2b9b..5c5467c5 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -14,7 +14,7 @@ use std::time::{Duration, Instant};
const GIT_REMOTE_STATUS_REFRESH_INTERVAL: Duration = Duration::from_millis(1500);
const SIDEBAR_DOUBLE_CLICK_WINDOW: Duration = Duration::from_millis(350);
-use crossterm::event::{self, Event, KeyEventKind};
+use crossterm::terminal;
use ratatui::layout::Rect;
use ratatui::DefaultTerminal;
use tokio::sync::mpsc;
@@ -35,6 +35,8 @@ pub struct App {
event_hub: crate::api::EventHub,
last_focus: Option<(usize, crate::layout::PaneId)>,
no_session: bool,
+ input_rx: Option<mpsc::Receiver<crate::raw_input::RawInputEvent>>,
+ last_terminal_size: Option<(u16, u16)>,
config_diagnostic_deadline: Option<Instant>,
toast_deadline: Option<Instant>,
last_git_remote_status_refresh: Instant,
@@ -192,10 +194,16 @@ impl App {
event_hub,
last_focus,
no_session,
+ input_rx: None,
+ last_terminal_size: terminal::size().ok(),
}
}
pub async fn run(&mut self, terminal: &mut DefaultTerminal) -> io::Result<()> {
+ if self.input_rx.is_none() {
+ self.input_rx = Some(crate::raw_input::spawn_input_reader());
+ }
+
while !self.state.should_quit {
if self
.config_diagnostic_deadline
@@ -236,18 +244,10 @@ impl App {
}
self.sync_focus_events();
+ self.handle_resize_poll();
+ self.drain_raw_input().await;
- if event::poll(Duration::from_millis(16))? {
- match event::read()? {
- Event::Key(key) if key.kind == KeyEventKind::Press => {
- self.handle_key(key).await;
- }
- Event::Paste(text) => self.handle_paste(text).await,
- Event::Mouse(mouse) => self.handle_mouse(mouse),
- Event::Resize(_, _) => {}
- _ => {}
- }
- }
+ tokio::time::sleep(Duration::from_millis(16)).await;
if self.state.request_complete_onboarding {
self.state.request_complete_onboarding = false;
@@ -273,6 +273,33 @@ impl App {
Ok(())
}
+ async fn drain_raw_input(&mut self) {
+ while let Some(rx) = self.input_rx.as_mut() {
+ match rx.try_recv() {
+ Ok(crate::raw_input::RawInputEvent::Key(key)) => {
+ if key.kind == crossterm::event::KeyEventKind::Press {
+ self.handle_key(key).await;
+ }
+ }
+ Ok(crate::raw_input::RawInputEvent::Paste(text)) => self.handle_paste(text).await,
+ Ok(crate::raw_input::RawInputEvent::Mouse(mouse)) => self.handle_mouse(mouse),
+ Ok(crate::raw_input::RawInputEvent::Unsupported) => {}
+ Err(tokio::sync::mpsc::error::TryRecvError::Empty) => break,
+ Err(tokio::sync::mpsc::error::TryRecvError::Disconnected) => {
+ self.input_rx = None;
+ break;
+ }
+ }
+ }
+ }
+
+ fn handle_resize_poll(&mut self) {
+ let Ok(size) = terminal::size() else { return };
+ if self.last_terminal_size != Some(size) {
+ self.last_terminal_size = Some(size);
+ }
+ }
+
fn drain_internal_events(&mut self) {
while let Ok(ev) = self.event_rx.try_recv() {
match &ev {
@@ -871,11 +898,14 @@ impl App {
})
.unwrap();
};
- let kitty = runtime
+ let flags = runtime
.1
- .kitty_keyboard
+ .kitty_keyboard_flags
.load(std::sync::atomic::Ordering::Relaxed);
- let bytes = crate::input::encode_key(key_event, kitty);
+ let bytes = crate::input::encode_key(
+ key_event,
+ crate::input::KeyboardProtocol::from_kitty_flags(flags),
+ );
if let Err(err) = runtime.0.try_send(Bytes::from(bytes)) {
return serde_json::to_string(&ErrorResponse {
id: request.id,