fix: stack ordering command (#4308)

* fix: some issues with stacking panes

* cleanups and formatting

* docs(changelog): add PR
This commit is contained in:
Aram Drevekenin 2025-07-21 09:40:43 +02:00 committed by GitHub
parent 48ecb0e34f
commit 7d970c7090
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 22 additions and 26 deletions

View file

@ -23,6 +23,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* fix: out of bounds mouse release events (https://github.com/zellij-org/zellij/pull/4300) * fix: out of bounds mouse release events (https://github.com/zellij-org/zellij/pull/4300)
* fix: account for emoji/widechars when double/triple-clicking to mark words (https://github.com/zellij-org/zellij/pull/4302) * fix: account for emoji/widechars when double/triple-clicking to mark words (https://github.com/zellij-org/zellij/pull/4302)
* fix: allow pasting and emojis in tab/pane names and pasting in search (https://github.com/zellij-org/zellij/pull/4303) * fix: allow pasting and emojis in tab/pane names and pasting in search (https://github.com/zellij-org/zellij/pull/4303)
* fix: stack pane ordering when stacking multiple panes (https://github.com/zellij-org/zellij/pull/4308)
## [0.42.2] - 2025-04-15 ## [0.42.2] - 2025-04-15
* refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082) * refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082)

View file

@ -186,20 +186,29 @@ impl App {
fn update_grouped_panes(&mut self, pane_manifest: &PaneManifest, own_client_id: ClientId) { fn update_grouped_panes(&mut self, pane_manifest: &PaneManifest, own_client_id: ClientId) {
self.grouped_panes.clear(); self.grouped_panes.clear();
let mut count = 0; let mut count = 0;
let mut panes_with_index = Vec::new();
for (_tab_index, pane_infos) in &pane_manifest.panes { for (_tab_index, pane_infos) in &pane_manifest.panes {
for pane_info in pane_infos { for pane_info in pane_infos {
if pane_info.index_in_pane_group.get(&own_client_id).is_some() { if let Some(index_in_pane_group) = pane_info.index_in_pane_group.get(&own_client_id)
{
let pane_id = if pane_info.is_plugin { let pane_id = if pane_info.is_plugin {
PaneId::Plugin(pane_info.id) PaneId::Plugin(pane_info.id)
} else { } else {
PaneId::Terminal(pane_info.id) PaneId::Terminal(pane_info.id)
}; };
self.grouped_panes.push(pane_id); panes_with_index.push((*index_in_pane_group, pane_id));
count += 1; count += 1;
} }
} }
} }
panes_with_index.sort_by_key(|(index, _)| *index);
for (_, pane_id) in panes_with_index {
self.grouped_panes.push(pane_id);
}
if count == 0 { if count == 0 {
self.close_self(); self.close_self();
} }

View file

@ -2768,13 +2768,14 @@ impl Screen {
} }
} }
pub fn stack_panes(&mut self, mut pane_ids_to_stack: Vec<PaneId>) -> Option<PaneId> { pub fn stack_panes(&mut self, mut pane_ids_to_stack: Vec<PaneId>) -> Option<PaneId> {
// if successful, returns the pane id of the root pane // if successful, returns the pane id of the last pane in the stack
if pane_ids_to_stack.is_empty() { if pane_ids_to_stack.is_empty() {
log::error!("Got an empty list of pane_ids to stack"); log::error!("Got an empty list of pane_ids to stack");
return None; return None;
} }
let stack_size = pane_ids_to_stack.len(); let stack_size = pane_ids_to_stack.len();
let root_pane_id = pane_ids_to_stack.remove(0); let root_pane_id = pane_ids_to_stack.remove(0);
let last_pane_id = pane_ids_to_stack.last();
let Some(root_tab_id) = self let Some(root_tab_id) = self
.tabs .tabs
.iter() .iter()
@ -2824,7 +2825,7 @@ impl Screen {
self.tabs self.tabs
.get_mut(&root_tab_id) .get_mut(&root_tab_id)
.map(|t| t.stack_panes(root_pane_id, panes_to_stack)); .map(|t| t.stack_panes(root_pane_id, panes_to_stack));
return Some(root_pane_id); return last_pane_id.copied();
} }
pub fn change_floating_panes_coordinates( pub fn change_floating_panes_coordinates(
&mut self, &mut self,
@ -5470,8 +5471,8 @@ pub(crate) fn screen_thread_main(
screen.set_floating_pane_pinned(pane_id, should_be_pinned); screen.set_floating_pane_pinned(pane_id, should_be_pinned);
}, },
ScreenInstruction::StackPanes(pane_ids_to_stack, client_id) => { ScreenInstruction::StackPanes(pane_ids_to_stack, client_id) => {
if let Some(root_pane_id) = screen.stack_panes(pane_ids_to_stack) { if let Some(last_pane_id) = screen.stack_panes(pane_ids_to_stack) {
let _ = screen.focus_pane_with_id(root_pane_id, false, client_id); let _ = screen.focus_pane_with_id(last_pane_id, false, client_id);
let _ = screen.unblock_input(); let _ = screen.unblock_input();
let _ = screen.render(None); let _ = screen.render(None);
let pane_group = screen.get_client_pane_group(&client_id); let pane_group = screen.get_client_pane_group(&client_id);

View file

@ -5278,24 +5278,9 @@ impl Tab {
} }
self.swap_layouts.set_is_tiled_damaged(); // TODO: verify we can do all the below first self.swap_layouts.set_is_tiled_damaged(); // TODO: verify we can do all the below first
if self.pane_is_stacked(root_pane_id) { if self.pane_is_stacked(root_pane_id) {
if let Some(lowest_pane_id_in_stack) = self
.tiled_panes
.pane_ids_in_stack_of_pane_id(&root_pane_id)
.last()
{
// we get lowest_pane_id_in_stack so that we can extract the pane below and re-add
// it to its own stack - this has the effect of making it the last pane in the
// stack so that the rest of the panes will later be added below it - which makes
// sense from the perspective of the user
if let Some(pane) = self.extract_pane(root_pane_id, true) {
self.tiled_panes
.add_pane_to_stack(&lowest_pane_id_in_stack, pane);
}
}
for pane in panes_to_stack.drain(..) { for pane in panes_to_stack.drain(..) {
self.tiled_panes.add_pane_to_stack(&root_pane_id, pane); self.tiled_panes.add_pane_to_stack(&root_pane_id, pane);
} }
self.tiled_panes.expand_pane_in_stack(root_pane_id);
} else { } else {
// + 1 for the root pane // + 1 for the root pane
let mut stack_geoms = self let mut stack_geoms = self

View file

@ -3,12 +3,12 @@ source: zellij-server/src/./unit/screen_tests.rs
expression: "format!(\"{}\", snapshot)" expression: "format!(\"{}\", snapshot)"
--- ---
00 (C): ┌ Pane #1 ─────┐┌ Pane #2 ─────────────────────────────────────┐┌ Pane #5 ─────┐ 00 (C): ┌ Pane #1 ─────┐┌ Pane #2 ─────────────────────────────────────┐┌ Pane #5 ─────┐
01 (C): │ ││ ││ │ 01 (C): │ │┌ Pane #3 ─────────────────────────────────────┐│ │
02 (C): │ ││ ││ │ 02 (C): │ │┌ Pane #4 ─────────────────────────────────────┐│ │
03 (C): │ ││ ││ │ 03 (C): │ ││ ││ │
04 (C): │ ││ ││ │ 04 (C): │ ││ ││ │
05 (C): │ ││ ││ │ 05 (C): │ ││ ││ │
06 (C): │ ││ ││ │ 06 (C): │ ││ ││ │
07 (C): │ │└──────────────────────────────────────────────┘│ │ 07 (C): │ ││ ││ │
08 (C): │ │└ Pane #3 ─────────────────────────────────────┘│ │ 08 (C): │ ││ ││ │
09 (C): └──────────────┘└ Pane #4 ─────────────────────────────────────┘└──────────────┘ 09 (C): └──────────────┘└──────────────────────────────────────────────┘└──────────────┘