aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-08 22:23:41 +0200
committeruser <user@clank>2026-08-08 22:23:41 +0200
commita384c167725d99450dff8594c5ce42793feddcfb (patch)
tree342d61950d63aa5b50dcb7524f4a69464f065c87
parentsl0p: fix getting stuck in rename mode (base_mode wiped) (diff)
downloadsl0ppij-a384c167725d99450dff8594c5ce42793feddcfb.tar.gz
sl0ppij-a384c167725d99450dff8594c5ce42793feddcfb.tar.xz
sl0ppij-a384c167725d99450dff8594c5ce42793feddcfb.zip
sl0p: route mouse rename through the server, fixing stuck rename mode
Enter/Esc still did not leave rename mode after entering it by double-click. The previous attempt fixed a real trap (a None base_mode makes change_to_default_mode a silent no-op) but not this one. The actual cause: zellij tracks the client's input mode in TWO places. - Screen's ModeInfo, which drives what is rendered. - SessionData::current_input_modes on the server, which is what ROUTES key input to the right handler. The double-click path sent ScreenInstruction::ChangeMode directly, so only the first was updated: the rename prompt appeared and accepted text, while the server still interpreted keys in the previous mode - so Enter and Esc were never treated as rename-mode keys and there was no way out. Action::SwitchToMode (the rename keybind) sends ServerInstruction::ChangeMode instead, and the server handler updates current_input_modes AND derives base_mode from the session config before forwarding to Screen. The mouse path now sends exactly that, so it is the same code path as the keybind rather than an imitation of it. Tab::client_base_mode is dropped: the server supplies base_mode correctly, so it is no longer needed. Lesson worth keeping: 'send the instruction the existing feature sends' beats reconstructing its effects downstream. Both bugs here came from entering the system one layer too low. Baselines held: zellij-server 1429/30.
-rw-r--r--zellij-server/src/tab/mod.rs14
-rw-r--r--zellij-server/src/tab/mouse_handler.rs20
2 files changed, 13 insertions, 21 deletions
diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs
index 5792c0bc..be326868 100644
--- a/zellij-server/src/tab/mod.rs
+++ b/zellij-server/src/tab/mod.rs
@@ -7499,20 +7499,6 @@ impl Tab {
pub fn update_mouse_hover_effects(&mut self, mouse_hover_effects: bool) {
self.mouse_hover_effects = mouse_hover_effects;
}
- /// The mode this client returns to when it leaves a temporary mode.
- ///
- /// Screen::change_mode OVERWRITES ModeInfo::base_mode with whatever it is
- /// given, and ModeInfo::change_to_default_mode is a no-op when base_mode is
- /// None. Passing None therefore does not mean "leave it alone", it means
- /// "this client can never return to its base mode" - i.e. permanently stuck
- /// in the mode you just set.
- pub fn client_base_mode(&self, client_id: ClientId) -> Option<InputMode> {
- self.mode_info
- .borrow()
- .get(&client_id)
- .and_then(|mode_info| mode_info.base_mode)
- .or(self.default_mode_info.base_mode)
- }
/// Is this client currently typing into a modal prompt (renaming a pane or
/// tab, entering a search term)?
///
diff --git a/zellij-server/src/tab/mouse_handler.rs b/zellij-server/src/tab/mouse_handler.rs
index fc227bf1..5e1ced32 100644
--- a/zellij-server/src/tab/mouse_handler.rs
+++ b/zellij-server/src/tab/mouse_handler.rs
@@ -10,6 +10,7 @@ use crate::panes::grid::Click;
use crate::panes::PaneId;
use crate::plugins::PluginInstruction;
use crate::screen::{GuestModalOutcome, ScreenInstruction};
+use crate::ServerInstruction;
use crate::ClientId;
use super::{Pane, Tab};
@@ -791,15 +792,20 @@ impl MouseHandler {
clear_hover_for_client(tab, client_id);
tab.focus_pane_with_id(pane_id, false, false, client_id)
.with_context(err_context)?;
- // base_mode MUST be preserved: Screen::change_mode overwrites it,
- // and a None base_mode makes Esc/Enter a no-op, trapping the
- // client in RenamePane with no way out.
- let base_mode = tab.client_base_mode(client_id);
+ // Go through the SERVER, exactly as Action::SwitchToMode does
+ // for the rename keybind. Sending ScreenInstruction::ChangeMode
+ // directly only changes what Screen renders: the server keeps
+ // its own `current_input_modes` map, which is what routes key
+ // input, so bypassing it leaves the UI in RenamePane while keys
+ // are still interpreted in the previous mode - the prompt
+ // appears, and Enter/Esc never leave it.
+ //
+ // The server also derives base_mode from the session config, so
+ // this fixes the return path too.
tab.senders
- .send_to_screen(ScreenInstruction::ChangeMode(
- InputMode::RenamePane,
- base_mode,
+ .send_to_server(ServerInstruction::ChangeMode(
client_id,
+ InputMode::RenamePane,
None,
))
.with_context(err_context)?;