diff options
| author | Aram Drevekenin <aram@poor.dev> | 2025-07-22 09:13:41 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-22 09:13:41 +0200 |
| commit | 6af82a9e9985072b418b89ccca95b53d2aaa2794 (patch) | |
| tree | 4527fe4b7ee3c97cb4306f4ea4275755f8046da8 /default-plugins/multiple-select/src/main.rs | |
| parent | fix(compact-bar): tooltip duplication (#4310) (diff) | |
| download | sl0ppij-6af82a9e9985072b418b89ccca95b53d2aaa2794.tar.gz sl0ppij-6af82a9e9985072b418b89ccca95b53d2aaa2794.tar.xz sl0ppij-6af82a9e9985072b418b89ccca95b53d2aaa2794.zip | |
fix(plugins): multiple-select + compact-bar tooltip multiplayer issues (#4312)
* fix: allow stacking panes if root pane is floating
* fix: handle multiple client gracefully in multiple select
* style(fmt): rustfmt
* fix compact-bar tooltip multiuser duplication
* style(fmt): rustfmt
Diffstat (limited to 'default-plugins/multiple-select/src/main.rs')
| -rw-r--r-- | default-plugins/multiple-select/src/main.rs | 124 |
1 files changed, 92 insertions, 32 deletions
diff --git a/default-plugins/multiple-select/src/main.rs b/default-plugins/multiple-select/src/main.rs index bd6a8a58..3e68e22a 100644 --- a/default-plugins/multiple-select/src/main.rs +++ b/default-plugins/multiple-select/src/main.rs @@ -11,6 +11,7 @@ pub struct App { total_tabs_in_session: Option<usize>, grouped_panes: Vec<PaneId>, grouped_panes_count: usize, + all_client_grouped_panes: BTreeMap<ClientId, Vec<PaneId>>, mode_info: ModeInfo, closing: bool, highlighted_at: Option<Instant>, @@ -47,6 +48,8 @@ impl ZellijPlugin for App { if self.closing { return false; } + intercept_key_presses(); // we do this here so that all clients (even those connected after + // load) will have their keys intercepted match event { Event::ModeUpdate(mode_info) => self.handle_mode_update(mode_info), Event::PaneUpdate(pane_manifest) => self.handle_pane_update(pane_manifest), @@ -59,13 +62,18 @@ impl ZellijPlugin for App { fn render(&mut self, rows: usize, cols: usize) { self.update_current_size(rows, cols); - let ui_width = self.calculate_ui_width(); - self.update_baseline_ui_width(ui_width); - let base_x = cols.saturating_sub(self.baseline_ui_width) / 2; - let base_y = rows.saturating_sub(8) / 2; - self.render_header(base_x, base_y); - self.render_shortcuts(base_x, base_y + 2); - self.render_controls(base_x, base_y + 7); + + if self.grouped_panes_count == 0 { + self.render_no_panes_message(rows, cols); + } else { + let ui_width = self.calculate_ui_width(); + self.update_baseline_ui_width(ui_width); + let base_x = cols.saturating_sub(self.baseline_ui_width) / 2; + let base_y = rows.saturating_sub(8) / 2; + self.render_header(base_x, base_y); + self.render_shortcuts(base_x, base_y + 2); + self.render_controls(base_x, base_y + 7); + } } } @@ -88,7 +96,7 @@ impl App { let controls_width = group_controls_length(&self.mode_info); let header_width = Self::header_text().0.len(); - let shortcuts_max_width = Self::shortcuts_max_width(); + let shortcuts_max_width = self.shortcuts_max_width(); std::cmp::max( controls_width, @@ -96,6 +104,20 @@ impl App { ) } + fn render_no_panes_message(&self, rows: usize, cols: usize) { + let message = "PANES SELECTED FOR OTHER CLIENT"; + let message_component = Text::new(message).color_all(2); + let base_x = cols.saturating_sub(message.len()) / 2; + let base_y = rows / 2; + print_text_with_coordinates(message_component, base_x, base_y, None, None); + + let esc_message = "<ESC> - close"; + let esc_message_component = Text::new(esc_message).color_substring(3, "<ESC>"); + let esc_base_x = cols.saturating_sub(esc_message.len()) / 2; + let esc_base_y = base_y + 2; + print_text_with_coordinates(esc_message_component, esc_base_x, esc_base_y, None, None); + } + fn header_text() -> (&'static str, Text) { let header_text = "<ESC> - cancel, <TAB> - move"; let header_text_component = Text::new(header_text) @@ -104,10 +126,10 @@ impl App { (header_text, header_text_component) } - fn shortcuts_max_width() -> usize { + fn shortcuts_max_width(&self) -> usize { std::cmp::max( std::cmp::max( - Self::group_actions_text().0.len(), + self.group_actions_text().0.len(), Self::shortcuts_line1_text().0.len(), ), std::cmp::max( @@ -117,10 +139,18 @@ impl App { ) } - fn group_actions_text() -> (&'static str, Text) { - let text = "GROUP ACTIONS"; - let component = Text::new(text).color_all(2); - (text, component) + fn group_actions_text(&self) -> (&'static str, Text) { + let count_text = if self.grouped_panes_count == 1 { + format!("GROUP ACTIONS ({} SELECTED PANE)", self.grouped_panes_count) + } else { + format!( + "GROUP ACTIONS ({} SELECTED PANES)", + self.grouped_panes_count + ) + }; + + let component = Text::new(&count_text).color_all(2); + (Box::leak(count_text.into_boxed_str()), component) } fn shortcuts_line1_text() -> (&'static str, Text) { @@ -164,7 +194,8 @@ impl App { return false; }; - self.update_grouped_panes(&pane_manifest, own_client_id); + self.update_all_client_grouped_panes(&pane_manifest); + self.update_own_grouped_panes(&pane_manifest, own_client_id); self.update_tab_info(&pane_manifest); self.total_tabs_in_session = Some(pane_manifest.panes.keys().count()); @@ -183,7 +214,28 @@ impl App { false } - fn update_grouped_panes(&mut self, pane_manifest: &PaneManifest, own_client_id: ClientId) { + fn update_all_client_grouped_panes(&mut self, pane_manifest: &PaneManifest) { + self.all_client_grouped_panes.clear(); + + for (_tab_index, pane_infos) in &pane_manifest.panes { + for pane_info in pane_infos { + for (client_id, _index_in_pane_group) in &pane_info.index_in_pane_group { + let pane_id = if pane_info.is_plugin { + PaneId::Plugin(pane_info.id) + } else { + PaneId::Terminal(pane_info.id) + }; + + self.all_client_grouped_panes + .entry(*client_id) + .or_insert_with(Vec::new) + .push(pane_id); + } + } + } + } + + fn update_own_grouped_panes(&mut self, pane_manifest: &PaneManifest, own_client_id: ClientId) { self.grouped_panes.clear(); let mut count = 0; let mut panes_with_index = Vec::new(); @@ -209,20 +261,15 @@ impl App { self.grouped_panes.push(pane_id); } - if count == 0 { + if self.all_clients_have_empty_groups() { self.close_self(); } let previous_count = self.grouped_panes_count; self.grouped_panes_count = count; if let Some(own_plugin_id) = self.own_plugin_id { - let title = if count == 1 { - "SELECTED PANE" - } else { - "SELECTED PANES" - }; if previous_count != count { - rename_plugin_pane(own_plugin_id, format!("{} {}", count, title)); + rename_plugin_pane(own_plugin_id, "Multiple Pane Select".to_string()); } if previous_count != 0 && count != 0 && previous_count != count { if self.doherty_threshold_elapsed_since_highlight() { @@ -234,6 +281,12 @@ impl App { } } + fn all_clients_have_empty_groups(&self) -> bool { + self.all_client_grouped_panes + .values() + .all(|panes| panes.is_empty()) + } + fn doherty_threshold_elapsed_since_highlight(&self) -> bool { self.highlighted_at .map(|h| h.elapsed() >= std::time::Duration::from_millis(400)) @@ -266,7 +319,7 @@ impl App { BareKey::Char('c') => self.close_grouped_panes(), BareKey::Tab => self.next_coordinates(), BareKey::Esc => { - self.ungroup_panes_in_zellij(&self.grouped_panes.clone()); + self.ungroup_panes_in_zellij(); self.close_self(); }, _ => return false, @@ -290,7 +343,7 @@ impl App { fn render_shortcuts(&self, base_x: usize, base_y: usize) { let mut running_y = base_y; - print_text_with_coordinates(Self::group_actions_text().1, base_x, running_y, None, None); + print_text_with_coordinates(self.group_actions_text().1, base_x, running_y, None, None); running_y += 1; print_text_with_coordinates( @@ -337,28 +390,28 @@ impl App { self.execute_action_and_close(|pane_ids| { break_panes_to_new_tab(pane_ids, None, true); }); - self.ungroup_panes_in_zellij(&self.grouped_panes.clone()); + self.ungroup_panes_in_zellij(); } pub fn stack_grouped_panes(&mut self) { self.execute_action_and_close(|pane_ids| { stack_panes(pane_ids.to_vec()); }); - self.ungroup_panes_in_zellij(&self.grouped_panes.clone()); + self.ungroup_panes_in_zellij(); } pub fn float_grouped_panes(&mut self) { self.execute_action_and_close(|pane_ids| { float_multiple_panes(pane_ids.to_vec()); }); - self.ungroup_panes_in_zellij(&self.grouped_panes.clone()); + self.ungroup_panes_in_zellij(); } pub fn embed_grouped_panes(&mut self) { self.execute_action_and_close(|pane_ids| { embed_multiple_panes(pane_ids.to_vec()); }); - self.ungroup_panes_in_zellij(&self.grouped_panes.clone()); + self.ungroup_panes_in_zellij(); } pub fn break_grouped_panes_right(&mut self) { @@ -385,7 +438,7 @@ impl App { let pane_ids = self.grouped_panes.clone(); if own_tab_index > 0 { - break_panes_to_tab_with_index(&pane_ids, own_tab_index - 1, true); + break_panes_to_tab_with_index(&pane_ids, own_tab_index.saturating_sub(1), true); } else { break_panes_to_new_tab(&pane_ids, None, true); } @@ -399,9 +452,16 @@ impl App { }); } - pub fn ungroup_panes_in_zellij(&mut self, pane_ids: &[PaneId]) { - group_and_ungroup_panes(vec![], pane_ids.to_vec()); + pub fn ungroup_panes_in_zellij(&mut self) { + let all_grouped_panes: Vec<PaneId> = self + .all_client_grouped_panes + .values() + .flat_map(|panes| panes.iter().cloned()) + .collect(); + let for_all_clients = true; + group_and_ungroup_panes(vec![], all_grouped_panes, for_all_clients); } + pub fn close_self(&mut self) { self.closing = true; close_self(); |
