aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-04-29 23:14:38 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-04-29 23:14:38 +0300
commiteec56a56a9f891de7a130536044a3ff875af0567 (patch)
tree7773a1ea64718c0bdd7a833a556fc7dba2748f12 /src
parentded6d7bfa6d18fecbaba826837c586a4603cfdb5 (diff)
fix: restore double prefix passthrough in client mode
Diffstat (limited to 'src')
-rw-r--r--src/app/input/mod.rs5
-rw-r--r--src/app/input/navigate.rs31
-rw-r--r--src/app/mod.rs24
3 files changed, 55 insertions, 5 deletions
diff --git a/src/app/input/mod.rs b/src/app/input/mod.rs
index e2454861..3beeac6b 100644
--- a/src/app/input/mod.rs
+++ b/src/app/input/mod.rs
@@ -36,7 +36,7 @@ pub(crate) use self::{
handle_confirm_close_key, handle_context_menu_key, handle_global_menu_key,
handle_keybind_help_key, handle_rename_key, handle_resize_key,
},
- navigate::{handle_navigate_key, terminal_direct_navigation_action},
+ navigate::terminal_direct_navigation_action,
settings::open_settings,
};
use self::{
@@ -56,12 +56,13 @@ impl App {
pub(super) async fn handle_key(&mut self, key: TerminalKey) {
match self.state.mode {
Mode::Terminal => self.handle_terminal_key(key).await,
+ Mode::Navigate => self.handle_navigate_key(key),
_ => {
let key = key.as_key_event();
match self.state.mode {
Mode::Onboarding => self.handle_onboarding_key(key),
Mode::ReleaseNotes => self.handle_release_notes_key(key),
- Mode::Navigate => self.handle_navigate_key(key),
+ Mode::Navigate => unreachable!(),
Mode::RenameWorkspace | Mode::RenameTab => {
handle_rename_key(&mut self.state, key)
}
diff --git a/src/app/input/navigate.rs b/src/app/input/navigate.rs
index b961c6d3..d55eedea 100644
--- a/src/app/input/navigate.rs
+++ b/src/app/input/navigate.rs
@@ -1,5 +1,6 @@
use std::process::{Command, Stdio};
+use bytes::Bytes;
use crossterm::event::{KeyCode, KeyEvent};
use ratatui::layout::Direction;
@@ -8,6 +9,7 @@ use crate::{
state::{key_matches, AppState, Mode},
App,
},
+ input::TerminalKey,
layout::NavDirection,
};
@@ -68,10 +70,18 @@ pub(crate) fn terminal_direct_navigation_action(
}
impl App {
- pub(super) fn handle_navigate_key(&mut self, key: KeyEvent) {
+ pub(crate) fn handle_navigate_key(&mut self, raw_key: TerminalKey) {
+ let key = raw_key.as_key_event();
self.state.update_dismissed = true;
- if self.state.is_prefix(&key) || key.code == KeyCode::Esc {
+ if self.state.is_prefix(&key) {
+ if !self.pass_through_key_to_focused_pane(raw_key) {
+ leave_navigate_mode(&mut self.state);
+ }
+ return;
+ }
+
+ if key.code == KeyCode::Esc {
leave_navigate_mode(&mut self.state);
return;
}
@@ -90,6 +100,23 @@ impl App {
}
}
+ fn pass_through_key_to_focused_pane(&mut self, key: TerminalKey) -> bool {
+ let Some(ws) = self.state.active.and_then(|i| self.state.workspaces.get(i)) else {
+ return false;
+ };
+ let Some(rt) = ws.focused_runtime() else {
+ return false;
+ };
+
+ let bytes = rt.encode_terminal_key(key);
+ if bytes.is_empty() || rt.try_send_bytes(Bytes::from(bytes)).is_err() {
+ return false;
+ }
+
+ self.state.mode = Mode::Terminal;
+ true
+ }
+
fn launch_custom_command(&mut self, binding: crate::config::CustomCommandKeybind) {
let previous_toast = self.state.toast.clone();
let result = match binding.action {
diff --git a/src/app/mod.rs b/src/app/mod.rs
index 3d588403..9e437e62 100644
--- a/src/app/mod.rs
+++ b/src/app/mod.rs
@@ -784,7 +784,7 @@ impl App {
let key_event = key.as_key_event();
match self.state.mode {
Mode::Navigate => {
- input::handle_navigate_key(&mut self.state, key_event);
+ self.handle_navigate_key(key);
}
Mode::RenameWorkspace | Mode::RenameTab => {
input::handle_rename_key(&mut self.state, key_event);
@@ -1586,6 +1586,28 @@ mod tests {
}
#[tokio::test]
+ async fn route_client_input_double_prefix_passes_prefix_through_to_focused_pane() {
+ let mut app = test_app();
+ let mut workspace = Workspace::test_new("test");
+ let focused = workspace.focused_pane_id().unwrap();
+ let (runtime, mut rx) = PaneRuntime::test_with_channel(80, 24);
+ workspace.tabs[0].runtimes.insert(focused, runtime);
+ app.state.workspaces = vec![workspace];
+ app.state.active = Some(0);
+ app.state.selected = 0;
+ app.state.mode = Mode::Terminal;
+ app.state.prefix_code = KeyCode::Char('l');
+ app.state.prefix_mods = KeyModifiers::CONTROL;
+
+ app.route_client_input(vec![0x0c]);
+ assert_eq!(app.state.mode, Mode::Navigate);
+
+ app.route_client_input(vec![0x0c]);
+ assert_eq!(app.state.mode, Mode::Terminal);
+ assert_eq!(rx.recv().await.unwrap(), bytes::Bytes::from(vec![0x0c]));
+ }
+
+ #[tokio::test]
async fn route_client_input_reencodes_terminal_keys_for_focused_pane_protocol() {
let mut app = test_app();
let mut workspace = Workspace::test_new("test");