diff options
| author | user <user@clank> | 2026-08-08 22:23:41 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-08 22:23:41 +0200 |
| commit | a384c167725d99450dff8594c5ce42793feddcfb (patch) | |
| tree | 342d61950d63aa5b50dcb7524f4a69464f065c87 | |
| parent | sl0p: fix getting stuck in rename mode (base_mode wiped) (diff) | |
| download | sl0ppij-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.rs | 14 | ||||
| -rw-r--r-- | zellij-server/src/tab/mouse_handler.rs | 20 |
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)?; |
