diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c22301d..a3b6e220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## [Unreleased] -* feat: multiple select and bulk pane actions (https://github.com/zellij-org/zellij/pull/4169 and https://github.com/zellij-org/zellij/pull/4171) +* feat: multiple select and bulk pane actions (https://github.com/zellij-org/zellij/pull/4169 and https://github.com/zellij-org/zellij/pull/4171 and https://github.com/zellij-org/zellij/pull/4221) ## [0.42.2] - 2025-04-15 * refactor(terminal): track scroll_region as tuple rather than Option (https://github.com/zellij-org/zellij/pull/4082) diff --git a/default-plugins/compact-bar/src/line.rs b/default-plugins/compact-bar/src/line.rs index 43431446..5d50d527 100644 --- a/default-plugins/compact-bar/src/line.rs +++ b/default-plugins/compact-bar/src/line.rs @@ -2,7 +2,6 @@ use ansi_term::ANSIStrings; use unicode_width::UnicodeWidthStr; use crate::{LinePart, ARROW_SEPARATOR}; -use zellij_tile::prelude::actions::Action; use zellij_tile::prelude::*; use zellij_tile_utils::style; @@ -252,8 +251,6 @@ pub fn tab_line( mode: InputMode, active_swap_layout_name: &Option, is_swap_layout_dirty: bool, - mode_info: &ModeInfo, - grouped_pane_count: Option, ) -> Vec { let mut tabs_after_active = all_tabs.split_off(active_tab_index); let mut tabs_before_active = all_tabs; @@ -289,21 +286,15 @@ pub fn tab_line( if current_title_len < cols { let mut remaining_space = cols - current_title_len; let remaining_bg = palette.text_unselected.background; - let right_side_component = match grouped_pane_count { - Some(grouped_pane_count) => { - render_group_controls(mode_info, grouped_pane_count, remaining_space) - }, - None => swap_layout_status( - remaining_space, - active_swap_layout_name, - is_swap_layout_dirty, - mode, - &palette, - tab_separator(capabilities), - ), - }; - if let Some(right_side_component) = right_side_component { - remaining_space -= right_side_component.len; + if let Some(swap_layout_status) = swap_layout_status( + remaining_space, + active_swap_layout_name, + is_swap_layout_dirty, + mode, + &palette, + tab_separator(capabilities), + ) { + remaining_space -= swap_layout_status.len; let mut buffer = String::new(); for _ in 0..remaining_space { buffer.push_str(&style!(remaining_bg, remaining_bg).paint(" ").to_string()); @@ -313,7 +304,7 @@ pub fn tab_line( len: remaining_space, tab_index: None, }); - prefix.push(right_side_component); + prefix.push(swap_layout_status); } } @@ -382,274 +373,3 @@ fn swap_layout_status( None => None, } } - -fn render_group_controls( - help: &ModeInfo, - grouped_pane_count: usize, - max_len: usize, -) -> Option { - let currently_marking_group = help.currently_marking_pane_group.unwrap_or(false); - let keymap = help.get_mode_keybinds(); - let (common_modifiers, multiple_select_key, pane_group_toggle_key, group_mark_toggle_key) = { - let multiple_select_key = multiple_select_key(&keymap); - let pane_group_toggle_key = single_action_key(&keymap, &[Action::TogglePaneInGroup]); - let group_mark_toggle_key = single_action_key(&keymap, &[Action::ToggleGroupMarking]); - let common_modifiers = get_common_modifiers( - vec![ - multiple_select_key.iter().next(), - pane_group_toggle_key.iter().next(), - group_mark_toggle_key.iter().next(), - ] - .into_iter() - .filter_map(|k| k) - .collect(), - ); - let multiple_select_key: Vec = multiple_select_key - .iter() - .map(|k| k.strip_common_modifiers(&common_modifiers)) - .collect(); - let pane_group_toggle_key: Vec = pane_group_toggle_key - .iter() - .map(|k| k.strip_common_modifiers(&common_modifiers)) - .collect(); - let group_mark_toggle_key: Vec = group_mark_toggle_key - .iter() - .map(|k| k.strip_common_modifiers(&common_modifiers)) - .collect(); - ( - common_modifiers, - multiple_select_key, - pane_group_toggle_key, - group_mark_toggle_key, - ) - }; - let multiple_select_key = multiple_select_key - .iter() - .next() - .map(|key| format!("{}", key)) - .unwrap_or("UNBOUND".to_owned()); - let pane_group_toggle_key = pane_group_toggle_key - .iter() - .next() - .map(|key| format!("{}", key)) - .unwrap_or("UNBOUND".to_owned()); - let group_mark_toggle_key = group_mark_toggle_key - .iter() - .next() - .map(|key| format!("{}", key)) - .unwrap_or("UNBOUND".to_owned()); - let background = help.style.colors.text_unselected.background; - let foreground = help.style.colors.text_unselected.base; - let superkey_prefix_style = style!(foreground, background).bold(); - let common_modifier_text = if common_modifiers.is_empty() { - "".to_owned() - } else { - format!( - "{} + ", - common_modifiers - .iter() - .map(|c| c.to_string()) - .collect::>() - .join("-") - ) - }; - - // full - let full_selected_panes_text = if common_modifier_text.is_empty() { - format!("{} SELECTED PANES", grouped_pane_count) - } else { - format!("{} SELECTED PANES |", grouped_pane_count) - }; - let full_group_actions_text = format!("<{}> Group Actions", &multiple_select_key); - let full_toggle_group_text = format!("<{}> Toggle Group", &pane_group_toggle_key); - let full_group_mark_toggle_text = format!("<{}> Follow Focus", &group_mark_toggle_key); - let ribbon_paddings_len = 12; - let full_controls_line_len = full_selected_panes_text.chars().count() - + 1 - + common_modifier_text.chars().count() - + full_group_actions_text.chars().count() - + full_toggle_group_text.chars().count() - + full_group_mark_toggle_text.chars().count() - + ribbon_paddings_len - + 1; // 1 for the end padding - - // medium - let medium_selected_panes_text = if common_modifier_text.is_empty() { - format!("{} SELECTED", grouped_pane_count) - } else { - format!("{} SELECTED |", grouped_pane_count) - }; - let medium_group_actions_text = format!("<{}> Actions", &multiple_select_key); - let medium_toggle_group_text = format!("<{}> Toggle", &pane_group_toggle_key); - let medium_group_mark_toggle_text = format!("<{}> Follow", &group_mark_toggle_key); - let ribbon_paddings_len = 12; - let medium_controls_line_len = medium_selected_panes_text.chars().count() - + 1 - + common_modifier_text.chars().count() - + medium_group_actions_text.chars().count() - + medium_toggle_group_text.chars().count() - + medium_group_mark_toggle_text.chars().count() - + ribbon_paddings_len - + 1; // 1 for the end padding - - // short - let short_selected_panes_text = if common_modifier_text.is_empty() { - format!("{} SELECTED", grouped_pane_count) - } else { - format!("{} SELECTED |", grouped_pane_count) - }; - let short_group_actions_text = format!("<{}>", &multiple_select_key); - let short_toggle_group_text = format!("<{}>", &pane_group_toggle_key); - let short_group_mark_toggle_text = format!("<{}>", &group_mark_toggle_key); - let color_emphasis_range_end = if common_modifier_text.is_empty() { - 0 - } else { - 2 - }; - let ribbon_paddings_len = 12; - let short_controls_line_len = short_selected_panes_text.chars().count() - + 1 - + common_modifier_text.chars().count() - + short_group_actions_text.chars().count() - + short_toggle_group_text.chars().count() - + short_group_mark_toggle_text.chars().count() - + ribbon_paddings_len - + 1; // 1 for the end padding - - let ( - selected_panes_text, - group_actions_text, - toggle_group_text, - group_mark_toggle_text, - controls_line_len, - ) = if max_len >= full_controls_line_len { - ( - full_selected_panes_text, - full_group_actions_text, - full_toggle_group_text, - full_group_mark_toggle_text, - full_controls_line_len, - ) - } else if max_len >= medium_controls_line_len { - ( - medium_selected_panes_text, - medium_group_actions_text, - medium_toggle_group_text, - medium_group_mark_toggle_text, - medium_controls_line_len, - ) - } else if max_len >= short_controls_line_len { - ( - short_selected_panes_text, - short_group_actions_text, - short_toggle_group_text, - short_group_mark_toggle_text, - short_controls_line_len, - ) - } else { - return None; - }; - let selected_panes = serialize_text( - &Text::new(&selected_panes_text) - .color_range( - 3, - ..selected_panes_text - .chars() - .count() - .saturating_sub(color_emphasis_range_end), - ) - .opaque(), - ); - let group_actions_ribbon = serialize_ribbon( - &Text::new(&group_actions_text).color_range(0, 1..=multiple_select_key.chars().count()), - ); - let toggle_group_ribbon = serialize_ribbon( - &Text::new(&toggle_group_text).color_range(0, 1..=pane_group_toggle_key.chars().count()), - ); - let mut group_mark_toggle_ribbon = Text::new(&group_mark_toggle_text) - .color_range(0, 1..=group_mark_toggle_key.chars().count()); - if currently_marking_group { - group_mark_toggle_ribbon = group_mark_toggle_ribbon.selected(); - } - let group_mark_toggle_ribbon = serialize_ribbon(&group_mark_toggle_ribbon); - let controls_line = if common_modifiers.is_empty() { - format!( - "{} {}{}{}", - selected_panes, group_actions_ribbon, toggle_group_ribbon, group_mark_toggle_ribbon - ) - } else { - let common_modifier = - serialize_text(&Text::new(&common_modifier_text).color_range(0, ..).opaque()); - format!( - "{} {}{}{}{}", - selected_panes, - common_modifier, - group_actions_ribbon, - toggle_group_ribbon, - group_mark_toggle_ribbon - ) - }; - let remaining_space = max_len.saturating_sub(controls_line_len); - let mut padding = String::new(); - let mut padding_len = 0; - for _ in 0..remaining_space { - padding.push_str(&ANSIStrings(&[superkey_prefix_style.paint(" ")]).to_string()); - padding_len += 1; - } - Some(LinePart { - part: format!("{}{}", padding, controls_line), - len: controls_line_len + padding_len, - tab_index: None, - }) -} - -fn multiple_select_key(keymap: &[(KeyWithModifier, Vec)]) -> Vec { - let mut matching = keymap.iter().find_map(|(key, acvec)| { - let has_match = acvec - .iter() - .find(|a| a.launches_plugin("zellij:multiple-select")) // TODO: make this an alias - .is_some(); - if has_match { - Some(key.clone()) - } else { - None - } - }); - if let Some(matching) = matching.take() { - vec![matching] - } else { - vec![] - } -} - -fn single_action_key( - keymap: &[(KeyWithModifier, Vec)], - action: &[Action], -) -> Vec { - let mut matching = keymap.iter().find_map(|(key, acvec)| { - if acvec.iter().next() == action.iter().next() { - Some(key.clone()) - } else { - None - } - }); - if let Some(matching) = matching.take() { - vec![matching] - } else { - vec![] - } -} - -fn get_common_modifiers(mut keyvec: Vec<&KeyWithModifier>) -> Vec { - if keyvec.is_empty() { - return vec![]; - } - let mut common_modifiers = keyvec.pop().unwrap().key_modifiers.clone(); - for key in keyvec { - common_modifiers = common_modifiers - .intersection(&key.key_modifiers) - .cloned() - .collect(); - } - common_modifiers.into_iter().collect() -} diff --git a/default-plugins/compact-bar/src/main.rs b/default-plugins/compact-bar/src/main.rs index d4a43ab8..91924211 100644 --- a/default-plugins/compact-bar/src/main.rs +++ b/default-plugins/compact-bar/src/main.rs @@ -26,8 +26,6 @@ struct State { tab_line: Vec, text_copy_destination: Option, display_system_clipboard_failure: bool, - own_client_id: Option, - grouped_panes_count: Option, } static ARROW_SEPARATOR: &str = ""; @@ -46,7 +44,6 @@ impl ZellijPlugin for State { EventType::SystemClipboardFailure, EventType::PaneUpdate, ]); - self.own_client_id = Some(get_plugin_ids().client_id); } fn update(&mut self, event: Event) -> bool { @@ -112,28 +109,6 @@ impl ZellijPlugin for State { self.text_copy_destination = None; self.display_system_clipboard_failure = false; }, - Event::PaneUpdate(pane_manifest) => { - if let Some(own_client_id) = self.own_client_id { - let mut grouped_panes_count = 0; - for (_tab_index, pane_infos) in pane_manifest.panes { - for pane_info in pane_infos { - let is_in_pane_group = - pane_info.index_in_pane_group.get(&own_client_id).is_some(); - if is_in_pane_group { - grouped_panes_count += 1; - } - } - } - if Some(grouped_panes_count) != self.grouped_panes_count { - if grouped_panes_count == 0 { - self.grouped_panes_count = None; - } else { - self.grouped_panes_count = Some(grouped_panes_count); - } - should_render = true; - } - } - }, _ => { eprintln!("Got unrecognized event: {:?}", event); }, @@ -207,8 +182,6 @@ impl ZellijPlugin for State { self.mode_info.mode, &active_swap_layout_name, is_swap_layout_dirty, - &self.mode_info, - self.grouped_panes_count, ); let output = self .tab_line diff --git a/default-plugins/configuration/src/presets.rs b/default-plugins/configuration/src/presets.rs index 54713635..abe26afc 100644 --- a/default-plugins/configuration/src/presets.rs +++ b/default-plugins/configuration/src/presets.rs @@ -168,12 +168,6 @@ keybinds clear-defaults=true {{ bind "{secondary_modifier} -" {{ Resize "Decrease"; }} bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - bind "{secondary_modifier} m" {{ - LaunchOrFocusPlugin "zellij:multiple-select" {{ - floating true - move_to_focused_tab true - }} - }} bind "{secondary_modifier} p" {{ TogglePaneInGroup; }} bind "{secondary_modifier} Shift p" {{ ToggleGroupMarking; }} }} @@ -400,12 +394,6 @@ keybinds clear-defaults=true {{ bind "{secondary_modifier} -" {{ Resize "Decrease"; }} bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - bind "{secondary_modifier} m" {{ - LaunchOrFocusPlugin "zellij:multiple-select" {{ - floating true - move_to_focused_tab true - }} - }} bind "{secondary_modifier} p" {{ TogglePaneInGroup; }} bind "{secondary_modifier} Shift p" {{ ToggleGroupMarking; }} }} @@ -611,12 +599,6 @@ keybinds clear-defaults=true {{ bind "{secondary_modifier} -" {{ Resize "Decrease"; }} bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - bind "{secondary_modifier} m" {{ - LaunchOrFocusPlugin "zellij:multiple-select" {{ - floating true - move_to_focused_tab true - }} - }} bind "{secondary_modifier} p" {{ TogglePaneInGroup; }} bind "{secondary_modifier} Shift p" {{ ToggleGroupMarking; }} }} @@ -1182,12 +1164,6 @@ keybinds clear-defaults=true {{ bind "{secondary_modifier} -" {{ Resize "Decrease"; }} bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - bind "{secondary_modifier} m" {{ - LaunchOrFocusPlugin "zellij:multiple-select" {{ - floating true - move_to_focused_tab true - }} - }} bind "{secondary_modifier} p" {{ TogglePaneInGroup; }} bind "{secondary_modifier} Shift p" {{ ToggleGroupMarking; }} }} diff --git a/default-plugins/multiple-select/src/main.rs b/default-plugins/multiple-select/src/main.rs index 773fd6fb..6bcd9b9b 100644 --- a/default-plugins/multiple-select/src/main.rs +++ b/default-plugins/multiple-select/src/main.rs @@ -1,9 +1,6 @@ -pub mod state; -pub mod ui; - -use state::{MarkedIndex, VisibilityAndFocus}; use std::collections::BTreeMap; -use ui::PaneItem; +use std::time::Instant; +use zellij_tile::prelude::actions::Action; use zellij_tile::prelude::*; #[derive(Debug, Default)] @@ -12,13 +9,17 @@ pub struct App { own_client_id: Option, own_tab_index: Option, total_tabs_in_session: Option, - search_string: String, - previous_search_string: String, // used eg. for the new tab title when breaking panes - left_side_panes: Vec, - right_side_panes: Vec, - search_results: Option>, - visibility_and_focus: VisibilityAndFocus, - marked_index: Option, + grouped_panes: Vec, + grouped_panes_count: usize, + mode_info: ModeInfo, + closing: bool, + highlighted_at: Option, + baseline_ui_width: usize, + current_rows: usize, + current_cols: usize, + display_area_rows: usize, + display_area_cols: usize, + alternate_coordinates: bool, } register_plugin!(App); @@ -27,186 +28,597 @@ impl ZellijPlugin for App { fn load(&mut self, _configuration: BTreeMap) { subscribe(&[ EventType::Key, - EventType::Mouse, + EventType::InterceptedKeyPress, EventType::ModeUpdate, - EventType::RunCommandResult, - EventType::TabUpdate, EventType::PaneUpdate, - EventType::FailedToWriteConfigToDisk, - EventType::ConfigWasWrittenToDisk, - EventType::BeforeClose, + EventType::TabUpdate, + EventType::Timer, ]); + let plugin_ids = get_plugin_ids(); self.own_plugin_id = Some(plugin_ids.plugin_id); self.own_client_id = Some(plugin_ids.client_id); - rename_plugin_pane(plugin_ids.plugin_id, "Multiple Select"); + + intercept_key_presses(); + set_selectable(false); } + fn update(&mut self, event: Event) -> bool { - let mut should_render = false; + if self.closing { + return false; + } match event { - Event::PaneUpdate(pane_manifest) => { - self.react_to_zellij_state_update(pane_manifest); - should_render = true; - }, - Event::Key(key) => { - match key.bare_key { - BareKey::Tab if key.has_no_modifiers() => { - self.visibility_and_focus.toggle_focus(); - self.marked_index = None; - self.update_highlighted_panes(); - should_render = true; - }, - BareKey::Char(character) - if key.has_no_modifiers() - && self.visibility_and_focus.left_side_is_focused() - && self.marked_index.is_none() => - { - self.search_string.push(character); - self.update_search_results(); - should_render = true; - }, - BareKey::Backspace - if key.has_no_modifiers() - && self.visibility_and_focus.left_side_is_focused() - && self.marked_index.is_none() => - { - self.search_string.pop(); - self.update_search_results(); - should_render = true; - }, - BareKey::Enter if key.has_no_modifiers() => { - if self.visibility_and_focus.left_side_is_focused() { - if let Some(marked_index) = self.marked_index.take() { - let keep_left_side_focused = false; - self.group_panes(marked_index, keep_left_side_focused); - } else { - match self.search_results.take() { - Some(search_results) => { - self.group_search_results(search_results) - }, - None => self.group_all_panes(), - } - self.handle_left_side_emptied(); - } - } - should_render = true; - }, - BareKey::Right - if key.has_no_modifiers() - && self.visibility_and_focus.left_side_is_focused() => - { - if let Some(marked_index) = self.marked_index.take() { - let keep_left_side_focused = true; - self.group_panes(marked_index, keep_left_side_focused); - should_render = true; - } - }, - BareKey::Left - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - if self.visibility_and_focus.right_side_is_focused() { - if let Some(marked_index) = self.marked_index.take() { - self.ungroup_panes(marked_index); - should_render = true; - } - } - }, - BareKey::Char('c') if key.has_modifiers(&[KeyModifier::Ctrl]) => { - if self.visibility_and_focus.right_side_is_focused() { - // this means we're in the selection panes part and we want to clear - // them - self.ungroup_all_panes(); - } else if self.visibility_and_focus.left_side_is_focused() { - if self.marked_index.is_some() { - self.marked_index = None; - self.update_highlighted_panes(); - } else { - self.ungroup_all_panes_and_close_self(); - } - } - should_render = true; - }, - BareKey::Down if key.has_no_modifiers() => { - self.move_marked_index_down(); - should_render = true; - }, - BareKey::Up if key.has_no_modifiers() => { - self.move_marked_index_up(); - should_render = true; - }, - BareKey::Char(' ') if key.has_no_modifiers() && self.marked_index.is_some() => { - self.mark_entry(); - should_render = true; - }, - BareKey::Char('b') - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - self.break_grouped_panes_to_new_tab(); - }, - BareKey::Char('s') - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - self.stack_grouped_panes(); - }, - BareKey::Char('f') - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - self.float_grouped_panes(); - }, - BareKey::Char('e') - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - self.embed_grouped_panes(); - }, - BareKey::Char('r') - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - self.break_grouped_panes_right(); - }, - BareKey::Char('l') - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - self.break_grouped_panes_left(); - }, - BareKey::Char('c') - if key.has_no_modifiers() - && self.visibility_and_focus.right_side_is_focused() => - { - self.close_grouped_panes(); - }, - _ => {}, - } - }, - Event::BeforeClose => { - self.unhighlight_all_panes(); - }, - _ => {}, + Event::ModeUpdate(mode_info) => self.handle_mode_update(mode_info), + Event::PaneUpdate(pane_manifest) => self.handle_pane_update(pane_manifest), + Event::TabUpdate(tab_infos) => self.handle_tab_update(tab_infos), + Event::InterceptedKeyPress(key) => self.handle_key_press(key), + Event::Timer(_) => self.handle_timer(), + _ => false, } - should_render } + fn render(&mut self, rows: usize, cols: usize) { - self.render_close_shortcut(cols); - self.render_tab_shortcut(cols, rows); - match self.visibility_and_focus { - VisibilityAndFocus::OnlyLeftSideVisible => self.render_left_side(rows, cols, true), - VisibilityAndFocus::OnlyRightSideVisible => self.render_right_side(rows, cols, true), - VisibilityAndFocus::BothSidesVisibleLeftSideFocused => { - self.render_left_side(rows, cols, true); - self.render_right_side(rows, cols, false); - }, - VisibilityAndFocus::BothSidesVisibleRightSideFocused => { - self.render_left_side(rows, cols, false); - self.render_right_side(rows, cols, true); - }, - } - self.render_focus_boundary(rows, cols); - self.render_help_line(rows, cols); + 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); } } + +impl App { + fn update_current_size(&mut self, new_rows: usize, new_cols: usize) { + let size_changed = new_rows != self.current_rows || new_cols != self.current_cols; + self.current_rows = new_rows; + self.current_cols = new_cols; + if size_changed { + self.baseline_ui_width = 0; + } + } + fn update_baseline_ui_width(&mut self, current_ui_width: usize) { + if current_ui_width > self.baseline_ui_width { + self.baseline_ui_width = current_ui_width; + } + } + + fn calculate_ui_width(&self) -> usize { + 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(); + + std::cmp::max( + controls_width, + std::cmp::max(header_width, shortcuts_max_width), + ) + } + + fn header_text() -> (&'static str, Text) { + let header_text = " - cancel, - move"; + let header_text_component = Text::new(header_text) + .color_substring(3, "") + .color_substring(3, ""); + (header_text, header_text_component) + } + + fn shortcuts_max_width() -> usize { + std::cmp::max( + std::cmp::max( + Self::group_actions_text().0.len(), + Self::shortcuts_line1_text().0.len(), + ), + std::cmp::max( + Self::shortcuts_line2_text().0.len(), + Self::shortcuts_line3_text().0.len(), + ), + ) + } + + fn group_actions_text() -> (&'static str, Text) { + let text = "GROUP ACTIONS"; + let component = Text::new(text).color_all(2); + (text, component) + } + + fn shortcuts_line1_text() -> (&'static str, Text) { + let text = " - break out, - stack, - close"; + let component = Text::new(text) + .color_substring(3, "") + .color_substring(3, "") + .color_substring(3, ""); + (text, component) + } + + fn shortcuts_line2_text() -> (&'static str, Text) { + let text = " - break right, - break left"; + let component = Text::new(text) + .color_substring(3, "") + .color_substring(3, ""); + (text, component) + } + + fn shortcuts_line3_text() -> (&'static str, Text) { + let text = " - embed, - float"; + let component = Text::new(text) + .color_substring(3, "") + .color_substring(3, ""); + (text, component) + } + + fn handle_mode_update(&mut self, mode_info: ModeInfo) -> bool { + if self.mode_info != mode_info { + self.mode_info = mode_info; + let ui_width = self.calculate_ui_width(); + self.update_baseline_ui_width(ui_width); + true + } else { + false + } + } + + fn handle_pane_update(&mut self, pane_manifest: PaneManifest) -> bool { + let Some(own_client_id) = self.own_client_id else { + return false; + }; + + self.update_grouped_panes(&pane_manifest, own_client_id); + self.update_tab_info(&pane_manifest); + self.total_tabs_in_session = Some(pane_manifest.panes.keys().count()); + + true + } + + fn handle_tab_update(&mut self, tab_infos: Vec) -> bool { + for tab in tab_infos { + if tab.active { + self.display_area_rows = tab.display_area_rows; + self.display_area_cols = tab.display_area_columns; + break; + } + } + + false + } + + fn update_grouped_panes(&mut self, pane_manifest: &PaneManifest, own_client_id: ClientId) { + self.grouped_panes.clear(); + let mut count = 0; + + for (_tab_index, pane_infos) in &pane_manifest.panes { + for pane_info in pane_infos { + if pane_info.index_in_pane_group.get(&own_client_id).is_some() { + let pane_id = if pane_info.is_plugin { + PaneId::Plugin(pane_info.id) + } else { + PaneId::Terminal(pane_info.id) + }; + self.grouped_panes.push(pane_id); + count += 1; + } + } + } + if count == 0 { + 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)); + } + if previous_count != 0 && count != 0 && previous_count != count { + if self.doherty_threshold_elapsed_since_highlight() { + self.highlighted_at = Some(Instant::now()); + highlight_and_unhighlight_panes(vec![PaneId::Plugin(own_plugin_id)], vec![]); + set_timeout(0.4); + } + } + } + } + + fn doherty_threshold_elapsed_since_highlight(&self) -> bool { + self.highlighted_at + .map(|h| h.elapsed() >= std::time::Duration::from_millis(400)) + .unwrap_or(true) + } + + fn update_tab_info(&mut self, pane_manifest: &PaneManifest) { + for (tab_index, pane_infos) in &pane_manifest.panes { + for pane_info in pane_infos { + if pane_info.is_plugin && Some(pane_info.id) == self.own_plugin_id { + self.own_tab_index = Some(*tab_index); + return; + } + } + } + } + + fn handle_key_press(&mut self, key: KeyWithModifier) -> bool { + if !key.has_no_modifiers() { + return false; + } + + match key.bare_key { + BareKey::Char('b') => self.break_grouped_panes_to_new_tab(), + BareKey::Char('s') => self.stack_grouped_panes(), + BareKey::Char('f') => self.float_grouped_panes(), + BareKey::Char('e') => self.embed_grouped_panes(), + BareKey::Char('r') => self.break_grouped_panes_right(), + BareKey::Char('l') => self.break_grouped_panes_left(), + BareKey::Char('c') => self.close_grouped_panes(), + BareKey::Tab => self.next_coordinates(), + BareKey::Esc => { + self.ungroup_panes_in_zellij(&self.grouped_panes.clone()); + self.close_self(); + }, + _ => return false, + } + false + } + fn handle_timer(&mut self) -> bool { + if let Some(own_plugin_id) = self.own_plugin_id { + if self.doherty_threshold_elapsed_since_highlight() { + highlight_and_unhighlight_panes(vec![], vec![PaneId::Plugin(own_plugin_id)]); + } + } + false + } + + fn render_header(&self, base_x: usize, base_y: usize) { + let header_text = Self::header_text(); + + print_text_with_coordinates(header_text.1, base_x, base_y, None, None); + } + + 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); + running_y += 1; + + print_text_with_coordinates( + Self::shortcuts_line1_text().1, + base_x, + running_y, + None, + None, + ); + running_y += 1; + + print_text_with_coordinates( + Self::shortcuts_line2_text().1, + base_x, + running_y, + None, + None, + ); + running_y += 1; + + print_text_with_coordinates( + Self::shortcuts_line3_text().1, + base_x, + running_y, + None, + None, + ); + } + + fn render_controls(&self, base_x: usize, base_y: usize) { + render_group_controls(&self.mode_info, base_x, base_y); + } + + fn execute_action_and_close(&mut self, action: F) + where + F: FnOnce(&[PaneId]), + { + let pane_ids = self.grouped_panes.clone(); + action(&pane_ids); + self.close_self(); + } + + pub fn break_grouped_panes_to_new_tab(&mut self) { + 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()); + } + + 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()); + } + + 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()); + } + + 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()); + } + + pub fn break_grouped_panes_right(&mut self) { + let Some(own_tab_index) = self.own_tab_index else { + return; + }; + + let pane_ids = self.grouped_panes.clone(); + + if Some(own_tab_index + 1) < self.total_tabs_in_session { + break_panes_to_tab_with_index(&pane_ids, own_tab_index + 1, true); + } else { + break_panes_to_new_tab(&pane_ids, None, true); + } + + self.close_self(); + } + + pub fn break_grouped_panes_left(&mut self) { + let Some(own_tab_index) = self.own_tab_index else { + return; + }; + + 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); + } else { + break_panes_to_new_tab(&pane_ids, None, true); + } + + self.close_self(); + } + + pub fn close_grouped_panes(&mut self) { + self.execute_action_and_close(|pane_ids| { + close_multiple_panes(pane_ids.to_vec()); + }); + } + + pub fn ungroup_panes_in_zellij(&mut self, pane_ids: &[PaneId]) { + group_and_ungroup_panes(vec![], pane_ids.to_vec()); + } + pub fn close_self(&mut self) { + self.closing = true; + close_self(); + } + pub fn next_coordinates(&mut self) { + let width_30_percent = (self.display_area_cols as f64 * 0.3) as usize; + let height_30_percent = (self.display_area_rows as f64 * 0.3) as usize; + let width = std::cmp::max(width_30_percent, 48); + let height = std::cmp::max(height_30_percent, 10); + let y_position = self.display_area_rows.saturating_sub(height + 2); + if let Some(own_plugin_id) = self.own_plugin_id { + if self.alternate_coordinates { + let x_position = 2; + let Some(next_coordinates) = FloatingPaneCoordinates::new( + Some(format!("{}", x_position)), + Some(format!("{}", y_position)), + Some(format!("{}", width)), + Some(format!("{}", height)), + Some(true), + ) else { + return; + }; + change_floating_panes_coordinates(vec![( + PaneId::Plugin(own_plugin_id), + next_coordinates, + )]); + self.alternate_coordinates = false; + } else { + let x_position = self + .display_area_cols + .saturating_sub(width) + .saturating_sub(2); + let Some(next_coordinates) = FloatingPaneCoordinates::new( + Some(format!("{}", x_position)), + Some(format!("{}", y_position)), + Some(format!("{}", width)), + Some(format!("{}", height)), + Some(true), + ) else { + return; + }; + change_floating_panes_coordinates(vec![( + PaneId::Plugin(own_plugin_id), + next_coordinates, + )]); + self.alternate_coordinates = true; + } + } + } +} + +fn render_group_controls(mode_info: &ModeInfo, base_x: usize, base_y: usize) { + let keymap = mode_info.get_mode_keybinds(); + let (common_modifiers, pane_group_key, group_mark_key) = extract_key_bindings(&keymap); + + let pane_group_bound = pane_group_key != "UNBOUND"; + let group_mark_bound = group_mark_key != "UNBOUND"; + + if !pane_group_bound && !group_mark_bound { + return; + } + + render_common_modifiers(&common_modifiers, base_x, base_y); + + let mut next_x = base_x + render_common_modifiers(&common_modifiers, base_x, base_y); + + if pane_group_bound { + next_x = render_toggle_group_ribbon(&pane_group_key, next_x, base_y); + } + + if group_mark_bound { + render_follow_focus_ribbon(&group_mark_key, next_x, base_y, mode_info); + } +} + +fn group_controls_length(mode_info: &ModeInfo) -> usize { + let keymap = mode_info.get_mode_keybinds(); + let (common_modifiers, pane_group_key, group_mark_key) = extract_key_bindings(&keymap); + + let pane_group_bound = pane_group_key != "UNBOUND"; + let group_mark_bound = group_mark_key != "UNBOUND"; + + let mut length = 0; + + if !common_modifiers.is_empty() { + let modifiers_text = format!( + "{} + ", + common_modifiers + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(" ") + ); + length += modifiers_text.chars().count(); + } + + if pane_group_bound { + let toggle_text = format!("<{}> Toggle", pane_group_key); + length += toggle_text.chars().count() + 4; + } + + if group_mark_bound { + let follow_text = format!("<{}> Follow Focus", group_mark_key); + length += follow_text.chars().count() + 4; + } + + length +} + +fn extract_key_bindings( + keymap: &[(KeyWithModifier, Vec)], +) -> (Vec, String, String) { + let pane_group_keys = get_key_for_action(keymap, &[Action::TogglePaneInGroup]); + let group_mark_keys = get_key_for_action(keymap, &[Action::ToggleGroupMarking]); + + let key_refs: Vec<&KeyWithModifier> = [pane_group_keys.first(), group_mark_keys.first()] + .into_iter() + .flatten() + .collect(); + + let common_modifiers = get_common_modifiers(key_refs); + + let pane_group_key = format_key_without_modifiers(&pane_group_keys, &common_modifiers); + let group_mark_key = format_key_without_modifiers(&group_mark_keys, &common_modifiers); + + (common_modifiers, pane_group_key, group_mark_key) +} + +fn format_key_without_modifiers( + keys: &[KeyWithModifier], + common_modifiers: &[KeyModifier], +) -> String { + keys.first() + .map(|key| format!("{}", key.strip_common_modifiers(&common_modifiers.to_vec()))) + .unwrap_or_else(|| "UNBOUND".to_string()) +} + +fn render_common_modifiers( + common_modifiers: &[KeyModifier], + base_x: usize, + base_y: usize, +) -> usize { + if !common_modifiers.is_empty() { + let modifiers_text = format!( + "{} + ", + common_modifiers + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(" ") + ); + + print_text_with_coordinates( + Text::new(&modifiers_text).color_all(0), + base_x, + base_y, + None, + None, + ); + + modifiers_text.chars().count() + } else { + 0 + } +} + +fn get_key_for_action( + keymap: &[(KeyWithModifier, Vec)], + target_action: &[Action], +) -> Vec { + keymap + .iter() + .find_map(|(key, actions)| { + if actions.first() == target_action.first() { + Some(key.clone()) + } else { + None + } + }) + .map(|key| vec![key]) + .unwrap_or_default() +} + +fn get_common_modifiers(keys: Vec<&KeyWithModifier>) -> Vec { + if keys.is_empty() { + return vec![]; + } + + let mut common = keys[0].key_modifiers.clone(); + + for key in keys.iter().skip(1) { + common = common.intersection(&key.key_modifiers).cloned().collect(); + } + + common.into_iter().collect() +} + +fn render_follow_focus_ribbon( + group_mark_key: &str, + x_position: usize, + base_y: usize, + mode_info: &ModeInfo, +) { + let follow_text = format!("<{}> Follow Focus", group_mark_key); + let key_highlight = format!("{}", group_mark_key); + + let mut ribbon = Text::new(&follow_text).color_substring(0, &key_highlight); + + if mode_info.currently_marking_pane_group.unwrap_or(false) { + ribbon = ribbon.selected(); + } + + print_ribbon_with_coordinates(ribbon, x_position, base_y, None, None); +} + +fn render_toggle_group_ribbon(pane_group_key: &str, base_x: usize, base_y: usize) -> usize { + let toggle_text = format!("<{}> Toggle", pane_group_key); + let key_highlight = format!("{}", pane_group_key); + + print_ribbon_with_coordinates( + Text::new(&toggle_text).color_substring(0, &key_highlight), + base_x, + base_y, + None, + None, + ); + + base_x + toggle_text.len() + 4 +} diff --git a/default-plugins/multiple-select/src/state.rs b/default-plugins/multiple-select/src/state.rs deleted file mode 100644 index 3bf863f8..00000000 --- a/default-plugins/multiple-select/src/state.rs +++ /dev/null @@ -1,634 +0,0 @@ -use crate::{ui::PaneItem, App}; -use std::collections::{BTreeMap, BTreeSet, HashSet}; - -use fuzzy_matcher::skim::SkimMatcherV2; -use fuzzy_matcher::FuzzyMatcher; - -use zellij_tile::prelude::*; - -#[derive(Debug, Default)] -pub struct MarkedIndex { - pub main_index: usize, - pub additional_indices: HashSet, -} - -impl MarkedIndex { - pub fn new(main_index: usize) -> Self { - MarkedIndex { - main_index, - additional_indices: HashSet::new(), - } - } -} - -impl MarkedIndex { - pub fn toggle_additional_mark(&mut self) { - if self.additional_indices.contains(&self.main_index) { - self.additional_indices.retain(|a| a != &self.main_index); - } else { - self.additional_indices.insert(self.main_index); - } - } -} - -#[derive(Debug)] -pub enum VisibilityAndFocus { - OnlyLeftSideVisible, - OnlyRightSideVisible, - BothSidesVisibleLeftSideFocused, - BothSidesVisibleRightSideFocused, -} - -impl Default for VisibilityAndFocus { - fn default() -> Self { - VisibilityAndFocus::OnlyLeftSideVisible - } -} - -impl VisibilityAndFocus { - pub fn only_left_side_is_focused(&self) -> bool { - match self { - VisibilityAndFocus::OnlyLeftSideVisible => true, - _ => false, - } - } - pub fn left_side_is_focused(&self) -> bool { - match self { - VisibilityAndFocus::OnlyLeftSideVisible - | VisibilityAndFocus::BothSidesVisibleLeftSideFocused => true, - _ => false, - } - } - pub fn right_side_is_focused(&self) -> bool { - match self { - VisibilityAndFocus::OnlyRightSideVisible - | VisibilityAndFocus::BothSidesVisibleRightSideFocused => true, - _ => false, - } - } - pub fn hide_left_side(&mut self) { - *self = VisibilityAndFocus::OnlyRightSideVisible - } - pub fn hide_right_side(&mut self) { - *self = VisibilityAndFocus::OnlyLeftSideVisible - } - pub fn focus_right_side(&mut self) { - *self = VisibilityAndFocus::BothSidesVisibleRightSideFocused - } - pub fn toggle_focus(&mut self) { - match self { - VisibilityAndFocus::BothSidesVisibleLeftSideFocused => { - *self = VisibilityAndFocus::BothSidesVisibleRightSideFocused - }, - VisibilityAndFocus::BothSidesVisibleRightSideFocused => { - *self = VisibilityAndFocus::BothSidesVisibleLeftSideFocused - }, - VisibilityAndFocus::OnlyLeftSideVisible => { - *self = VisibilityAndFocus::BothSidesVisibleRightSideFocused - }, - VisibilityAndFocus::OnlyRightSideVisible => { - *self = VisibilityAndFocus::BothSidesVisibleLeftSideFocused - }, - } - } - pub fn show_both_sides(&mut self) { - match self { - VisibilityAndFocus::OnlyLeftSideVisible => { - *self = VisibilityAndFocus::BothSidesVisibleLeftSideFocused - }, - VisibilityAndFocus::OnlyRightSideVisible => { - *self = VisibilityAndFocus::BothSidesVisibleRightSideFocused - }, - VisibilityAndFocus::BothSidesVisibleLeftSideFocused - | VisibilityAndFocus::BothSidesVisibleRightSideFocused => { - // no-op - }, - } - } -} - -impl App { - pub fn react_to_zellij_state_update(&mut self, pane_manifest: PaneManifest) { - let is_first_update = self.right_side_panes.is_empty() && self.left_side_panes.is_empty(); - let panes_on_the_left_before = self.left_side_panes.len(); - let panes_on_the_right_before = self.right_side_panes.len(); - self.update_tab_info(&pane_manifest); - self.update_panes(pane_manifest); - if is_first_update && !self.right_side_panes.is_empty() { - // in this case, the plugin was started with an existing group - // most likely, the user wants to perform operations just on this group, so we - // only show the group, giving the option to add more panes - self.visibility_and_focus.hide_left_side(); - } - let pane_count_changed = (panes_on_the_left_before != self.left_side_panes.len()) - || (panes_on_the_right_before != self.right_side_panes.len()); - if !is_first_update && pane_count_changed { - let has_panes_on_the_right = !self.right_side_panes.is_empty(); - let has_panes_on_the_left = !self.left_side_panes.is_empty(); - if has_panes_on_the_right && has_panes_on_the_left { - self.visibility_and_focus.show_both_sides(); - } else if has_panes_on_the_right { - self.visibility_and_focus.hide_left_side(); - } else if has_panes_on_the_left { - self.visibility_and_focus.hide_right_side(); - } - } - } - pub fn update_panes(&mut self, pane_manifest: PaneManifest) { - let mut all_panes = BTreeMap::new(); - for (_tab_index, pane_infos) in pane_manifest.panes { - for pane_info in pane_infos { - if pane_info.is_selectable { - if pane_info.is_plugin { - all_panes.insert(PaneId::Plugin(pane_info.id), pane_info); - } else { - all_panes.insert(PaneId::Terminal(pane_info.id), pane_info); - } - } - } - } - self.left_side_panes - .retain(|p| all_panes.contains_key(&p.id)); - self.right_side_panes - .retain(|p| all_panes.contains_key(&p.id)); - let mut new_selected_panes: BTreeMap = BTreeMap::new(); // usize -> index_in_pane_group - for (pane_id, pane) in all_panes.into_iter() { - let is_known = self - .left_side_panes - .iter() - .find(|p| p.id == pane_id) - .is_some() - || self - .right_side_panes - .iter() - .find(|p| p.id == pane_id) - .is_some(); - let index_in_pane_group = self - .own_client_id - .and_then(|own_client_id| pane.index_in_pane_group.get(&own_client_id)); - let is_grouped_for_own_client_id = index_in_pane_group.is_some(); - if !is_known { - if is_grouped_for_own_client_id { - if let Some(index_in_pane_group) = index_in_pane_group { - // we do this rather than adding them directly to right_side_panes so that - // we can make sure they're in the same order as the group is so that - // things like stacking order will do the right thing - new_selected_panes.insert( - *index_in_pane_group, - PaneItem { - text: pane.title, - id: pane_id, - color_indices: vec![], - }, - ); - } - } else { - self.left_side_panes.push(PaneItem { - text: pane.title, - id: pane_id, - color_indices: vec![], - }); - } - } else { - if is_grouped_for_own_client_id { - if let Some(position) = - self.left_side_panes.iter().position(|p| p.id == pane_id) - { - // pane was added to a pane group outside the plugin (eg. with mouse selection) - let mut pane = self.left_side_panes.remove(position); - pane.clear(); - self.right_side_panes.push(pane); - } - } else { - if let Some(position) = - self.right_side_panes.iter().position(|p| p.id == pane_id) - { - // pane was removed from a pane group outside the plugin (eg. with mouse selection) - let mut pane = self.right_side_panes.remove(position); - pane.clear(); - self.left_side_panes.push(pane); - } - } - } - } - for (_index_in_pane_group, pane_item) in new_selected_panes.into_iter() { - self.right_side_panes.push(pane_item); - } - } - pub fn update_tab_info(&mut self, pane_manifest: &PaneManifest) { - for (tab_index, pane_infos) in &pane_manifest.panes { - for pane_info in pane_infos { - if pane_info.is_plugin && Some(pane_info.id) == self.own_plugin_id { - self.own_tab_index = Some(*tab_index); - } - } - } - self.total_tabs_in_session = Some(pane_manifest.panes.keys().count()); - } - pub fn update_search_results(&mut self) { - let mut matches = vec![]; - let matcher = SkimMatcherV2::default().use_cache(true); - for pane_item in &self.left_side_panes { - if let Some((score, indices)) = - matcher.fuzzy_indices(&pane_item.text, &self.search_string) - { - let mut pane_item = pane_item.clone(); - pane_item.color_indices = indices; - matches.push((score, pane_item)); - } - } - matches.sort_by(|(a_score, _a), (b_score, _b)| b_score.cmp(&a_score)); - if self.search_string.is_empty() { - self.search_results = None; - } else { - self.search_results = Some( - matches - .into_iter() - .map(|(_s, pane_item)| pane_item) - .collect(), - ); - } - } - pub fn group_panes_in_zellij(&mut self, pane_ids: Vec) { - group_and_ungroup_panes(pane_ids, vec![]); - } - pub fn ungroup_panes_in_zellij(&mut self, pane_ids: Vec) { - group_and_ungroup_panes(vec![], pane_ids); - } - pub fn update_highlighted_panes(&self) { - let mut pane_ids_to_highlight = vec![]; - let mut pane_ids_to_unhighlight = vec![]; - if let Some(marked_index) = &self.marked_index { - if self.visibility_and_focus.left_side_is_focused() { - if let Some(main_index_pane_id) = self - .search_results - .as_ref() - .and_then(|s| s.get(marked_index.main_index)) - .or_else(|| self.left_side_panes.get(marked_index.main_index)) - .map(|p| p.id) - { - pane_ids_to_highlight.push(main_index_pane_id); - } - for index in &marked_index.additional_indices { - if let Some(pane_id) = self - .search_results - .as_ref() - .and_then(|s| s.get(*index)) - .or_else(|| self.left_side_panes.get(*index)) - .map(|p| p.id) - { - pane_ids_to_highlight.push(pane_id); - } - } - } else { - if let Some(main_index_pane_id) = self - .right_side_panes - .get(marked_index.main_index) - .map(|p| p.id) - { - pane_ids_to_highlight.push(main_index_pane_id); - } - for index in &marked_index.additional_indices { - if let Some(pane_id) = self.right_side_panes.get(*index).map(|p| p.id) { - pane_ids_to_highlight.push(pane_id); - } - } - } - } - for pane in &self.left_side_panes { - if !pane_ids_to_highlight.contains(&pane.id) { - pane_ids_to_unhighlight.push(pane.id); - } - } - for pane in &self.right_side_panes { - if !pane_ids_to_highlight.contains(&pane.id) { - pane_ids_to_unhighlight.push(pane.id); - } - } - highlight_and_unhighlight_panes(pane_ids_to_highlight, pane_ids_to_unhighlight); - } - pub fn unhighlight_all_panes(&mut self) { - let mut pane_ids_to_unhighlight = HashSet::new(); - for pane_item in &self.left_side_panes { - pane_ids_to_unhighlight.insert(pane_item.id); - } - for pane_item in &self.right_side_panes { - pane_ids_to_unhighlight.insert(pane_item.id); - } - highlight_and_unhighlight_panes(vec![], pane_ids_to_unhighlight.into_iter().collect()); - } - pub fn ungroup_all_panes(&mut self) { - let mut unselected_panes = vec![]; - for pane_item in self.right_side_panes.iter_mut() { - pane_item.clear(); - unselected_panes.push(pane_item.id); - } - self.left_side_panes.append(&mut self.right_side_panes); - self.ungroup_panes_in_zellij(unselected_panes); - self.visibility_and_focus.hide_right_side(); - self.marked_index = None; - } - pub fn ungroup_all_panes_and_close_self(&mut self) { - let mut pane_ids_to_ungroup = HashSet::new(); - for pane_item in &self.left_side_panes { - pane_ids_to_ungroup.insert(pane_item.id); - } - for pane_item in &self.right_side_panes { - pane_ids_to_ungroup.insert(pane_item.id); - } - group_and_ungroup_panes(vec![], pane_ids_to_ungroup.into_iter().collect()); - close_self(); - } - pub fn group_panes(&mut self, mut marked_index: MarkedIndex, keep_left_side_focused: bool) { - let mut all_selected_indices: BTreeSet = - marked_index.additional_indices.drain().collect(); - all_selected_indices.insert(marked_index.main_index); - - // reverse so that the indices will remain consistent while - // removing - let mut selected_panes = vec![]; - for index in all_selected_indices.iter().rev() { - let index = self - .search_results - .as_mut() - .and_then(|search_results| { - if search_results.len() > *index { - Some(search_results.remove(*index)) - } else { - None - } - }) - .and_then(|selected_search_result| { - self.left_side_panes - .iter() - .position(|p| p.id == selected_search_result.id) - }) - .unwrap_or(*index); - if self.left_side_panes.len() > index { - let selected_pane = self.left_side_panes.remove(index); - selected_panes.push(selected_pane); - } - } - let pane_ids_to_make_selected: Vec = selected_panes.iter().map(|p| p.id).collect(); - self.right_side_panes - .append(&mut selected_panes.into_iter().rev().collect()); - - let displayed_list_len = match self.search_results.as_ref() { - Some(search_results) => search_results.len(), - None => self.left_side_panes.len(), - }; - - if displayed_list_len == 0 { - self.handle_left_side_emptied(); - } else if keep_left_side_focused { - if marked_index.main_index > displayed_list_len.saturating_sub(1) { - self.marked_index = Some(MarkedIndex::new(displayed_list_len.saturating_sub(1))); - } else { - self.marked_index = Some(marked_index); - } - self.visibility_and_focus.show_both_sides(); - } else { - self.visibility_and_focus.focus_right_side(); - } - - self.group_panes_in_zellij(pane_ids_to_make_selected); - self.update_highlighted_panes(); - } - pub fn ungroup_panes(&mut self, mut marked_index: MarkedIndex) { - let mut all_selected_indices: BTreeSet = - marked_index.additional_indices.drain().collect(); - all_selected_indices.insert(marked_index.main_index); - - // reverse so that the indices will remain consistent while - // removing - let mut selected_panes = vec![]; - for index in all_selected_indices.iter().rev() { - if self.right_side_panes.len() > *index { - let mut selected_pane = self.right_side_panes.remove(*index); - selected_pane.clear(); - selected_panes.push(selected_pane); - } - } - self.ungroup_panes_in_zellij(selected_panes.iter().map(|p| p.id).collect()); - self.left_side_panes - .append(&mut selected_panes.into_iter().rev().collect()); - - if self.right_side_panes.is_empty() { - self.marked_index = None; - self.visibility_and_focus.hide_right_side(); - } else if marked_index.main_index > self.right_side_panes.len().saturating_sub(1) { - self.marked_index = Some(MarkedIndex::new( - self.right_side_panes.len().saturating_sub(1), - )); - self.visibility_and_focus.show_both_sides(); - } else { - self.marked_index = Some(marked_index); - self.visibility_and_focus.show_both_sides(); - } - self.update_highlighted_panes(); - } - pub fn group_search_results(&mut self, search_results: Vec) { - let mut pane_ids_to_make_selected = vec![]; - for search_result in search_results { - let pane_id = search_result.id; - pane_ids_to_make_selected.push(pane_id); - self.left_side_panes.retain(|p| p.id != pane_id); - self.right_side_panes.push(search_result); - } - self.group_panes_in_zellij(pane_ids_to_make_selected); - } - pub fn group_all_panes(&mut self) { - let pane_ids_to_make_selected: Vec = - self.left_side_panes.iter().map(|p| p.id).collect(); - self.right_side_panes.append(&mut self.left_side_panes); - self.group_panes_in_zellij(pane_ids_to_make_selected); - } - pub fn handle_left_side_emptied(&mut self) { - self.visibility_and_focus.hide_left_side(); - self.previous_search_string = self.search_string.drain(..).collect(); - self.marked_index = None; - self.search_results = None; - self.update_highlighted_panes(); - } - pub fn move_marked_index_down(&mut self) { - match self.marked_index.as_mut() { - Some(marked_index) => { - let is_searching = self.search_results.is_some(); - let search_result_count = - self.search_results.as_ref().map(|s| s.len()).unwrap_or(0); - if self.visibility_and_focus.left_side_is_focused() - && is_searching - && marked_index.main_index == search_result_count.saturating_sub(1) - { - marked_index.main_index = 0; - } else if self.visibility_and_focus.left_side_is_focused() - && !is_searching - && marked_index.main_index == self.left_side_panes.len().saturating_sub(1) - { - marked_index.main_index = 0; - } else if self.visibility_and_focus.right_side_is_focused() - && marked_index.main_index == self.right_side_panes.len().saturating_sub(1) - { - marked_index.main_index = 0; - } else { - marked_index.main_index += 1 - } - }, - None => { - if self.visibility_and_focus.left_side_is_focused() { - let is_searching = self.search_results.is_some(); - let has_search_results = self - .search_results - .as_ref() - .map(|s| !s.is_empty()) - .unwrap_or(false); - if is_searching && has_search_results { - self.marked_index = Some(MarkedIndex::new(0)); - } else if !is_searching && !self.left_side_panes.is_empty() { - self.marked_index = Some(MarkedIndex::new(0)); - } - } else if self.visibility_and_focus.right_side_is_focused() - && !self.right_side_panes.is_empty() - { - self.marked_index = Some(MarkedIndex::new(0)); - } - }, - } - self.update_highlighted_panes(); - } - pub fn move_marked_index_up(&mut self) { - match self.marked_index.as_mut() { - Some(marked_index) => { - if self.visibility_and_focus.left_side_is_focused() && marked_index.main_index == 0 - { - if let Some(search_result_count) = self.search_results.as_ref().map(|s| s.len()) - { - marked_index.main_index = search_result_count.saturating_sub(1); - } else { - marked_index.main_index = self.left_side_panes.len().saturating_sub(1); - } - } else if self.visibility_and_focus.right_side_is_focused() - && marked_index.main_index == 0 - { - marked_index.main_index = self.right_side_panes.len().saturating_sub(1); - } else { - marked_index.main_index = marked_index.main_index.saturating_sub(1); - } - }, - None => { - if self.visibility_and_focus.left_side_is_focused() { - let is_searching = self.search_results.is_some(); - let has_search_results = self - .search_results - .as_ref() - .map(|s| !s.is_empty()) - .unwrap_or(false); - if is_searching && has_search_results { - let search_results_count = - self.search_results.as_ref().map(|s| s.len()).unwrap_or(0); - self.marked_index = - Some(MarkedIndex::new(search_results_count.saturating_sub(1))); - } else if !is_searching && !self.left_side_panes.is_empty() { - self.marked_index = Some(MarkedIndex::new( - self.left_side_panes.len().saturating_sub(1), - )); - } - } else if self.visibility_and_focus.right_side_is_focused() - && !self.right_side_panes.is_empty() - { - self.marked_index = Some(MarkedIndex::new( - self.right_side_panes.len().saturating_sub(1), - )); - } - }, - } - self.update_highlighted_panes(); - } - pub fn mark_entry(&mut self) { - if let Some(marked_index) = self.marked_index.as_mut() { - marked_index.toggle_additional_mark(); - self.update_highlighted_panes(); - } - } - pub fn break_grouped_panes_to_new_tab(&mut self) { - let pane_ids_to_break_to_new_tab: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - let title_for_new_tab = if !self.previous_search_string.is_empty() { - Some(self.previous_search_string.clone()) - } else { - None - }; - break_panes_to_new_tab(&pane_ids_to_break_to_new_tab, title_for_new_tab, true); - self.ungroup_panes_in_zellij(pane_ids_to_break_to_new_tab); - close_self(); - } - pub fn stack_grouped_panes(&mut self) { - let pane_ids_to_stack: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - stack_panes(pane_ids_to_stack.clone()); - self.ungroup_panes_in_zellij(pane_ids_to_stack); - close_self(); - } - pub fn float_grouped_panes(&mut self) { - let pane_ids_to_float: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - float_multiple_panes(pane_ids_to_float.clone()); - self.ungroup_panes_in_zellij(pane_ids_to_float); - close_self(); - } - pub fn embed_grouped_panes(&mut self) { - let pane_ids_to_embed: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - embed_multiple_panes(pane_ids_to_embed.clone()); - self.ungroup_panes_in_zellij(pane_ids_to_embed); - close_self(); - } - pub fn break_grouped_panes_right(&mut self) { - if let Some(own_tab_index) = self.own_tab_index { - if Some(own_tab_index + 1) < self.total_tabs_in_session { - let pane_ids_to_break_right: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - break_panes_to_tab_with_index(&pane_ids_to_break_right, own_tab_index + 1, true); - } else { - let pane_ids_to_break_to_new_tab: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - let title_for_new_tab = if !self.previous_search_string.is_empty() { - Some(self.previous_search_string.clone()) - } else { - None - }; - break_panes_to_new_tab(&pane_ids_to_break_to_new_tab, title_for_new_tab, true); - } - close_self(); - } - } - pub fn break_grouped_panes_left(&mut self) { - if let Some(own_tab_index) = self.own_tab_index { - if own_tab_index > 0 { - let pane_ids_to_break_left: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - break_panes_to_tab_with_index( - &pane_ids_to_break_left, - own_tab_index.saturating_sub(1), - true, - ); - } else { - let pane_ids_to_break_to_new_tab: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - let title_for_new_tab = if !self.previous_search_string.is_empty() { - Some(self.previous_search_string.clone()) - } else { - None - }; - break_panes_to_new_tab(&pane_ids_to_break_to_new_tab, title_for_new_tab, true); - } - close_self(); - } - } - pub fn close_grouped_panes(&mut self) { - let pane_ids_to_close: Vec = - self.right_side_panes.drain(..).map(|p| p.id).collect(); - close_multiple_panes(pane_ids_to_close); - close_self(); - } -} diff --git a/default-plugins/multiple-select/src/ui.rs b/default-plugins/multiple-select/src/ui.rs deleted file mode 100644 index 0c74b0fe..00000000 --- a/default-plugins/multiple-select/src/ui.rs +++ /dev/null @@ -1,873 +0,0 @@ -use crate::{App, VisibilityAndFocus}; -use zellij_tile::prelude::*; - -const TOP_LEFT_CORNER_CHARACTER: &'static str = "┌"; -const TOP_RIGHT_CORNER_CHARACTER: &'static str = "┐"; -const BOTTOM_LEFT_CORNER_CHARACTER: &'static str = "└"; -const BOTTOM_RIGHT_CORNER_CHARACTER: &'static str = "┘"; -const BOUNDARY_CHARACTER: &'static str = "│"; -const HORIZONTAL_BOUNDARY_CHARACTER: &'static str = "─"; - -#[derive(Debug, Clone)] -pub struct PaneItem { - pub text: String, - pub id: PaneId, - pub color_indices: Vec, -} - -impl PaneItem { - pub fn clear(&mut self) { - self.color_indices.clear(); - } - pub fn render(&self, max_width_for_item: usize) -> NestedListItem { - let pane_item_text_len = self.text.chars().count(); - if pane_item_text_len <= max_width_for_item { - NestedListItem::new(&self.text) - .color_range(0, ..) - .color_indices(3, self.color_indices.iter().copied().collect()) - } else { - let length_of_each_half = max_width_for_item.saturating_sub(3) / 2; - let first_half: String = self.text.chars().take(length_of_each_half).collect(); - let second_half: String = self - .text - .chars() - .rev() - .take(length_of_each_half) - .collect::>() - .iter() - .rev() - .collect(); - let second_half_start_index = pane_item_text_len.saturating_sub(length_of_each_half); - let adjusted_indices: Vec = self - .color_indices - .iter() - .filter_map(|i| { - if i < &length_of_each_half { - Some(*i) - } else if i >= &second_half_start_index { - Some(i.saturating_sub(second_half_start_index) + length_of_each_half + 3) - //3 for the bulletin - } else { - None - } - }) - .collect(); - NestedListItem::new(format!("{}...{}", first_half, second_half)) - .color_range(0, ..) - .color_indices(3, adjusted_indices) - } - } -} - -// rendering code -impl App { - pub fn render_close_shortcut(&self, cols: usize) { - let should_render_close_shortcut = - self.visibility_and_focus.left_side_is_focused() && self.marked_index.is_none(); - if should_render_close_shortcut { - let x_coordinates_right_padding = - if self.visibility_and_focus.only_left_side_is_focused() { - 5 - } else { - 1 - }; - let ctrl_c_shortcut_text = " - Close"; - let ctrl_c_shortcut = Text::new(ctrl_c_shortcut_text).color_range(3, ..=7); - print_text_with_coordinates( - ctrl_c_shortcut, - cols.saturating_sub(ctrl_c_shortcut_text.chars().count()) - .saturating_sub(x_coordinates_right_padding), - 0, - None, - None, - ); - } - } - pub fn render_tab_shortcut(&self, cols: usize, rows: usize) { - match self.visibility_and_focus { - VisibilityAndFocus::BothSidesVisibleRightSideFocused => { - let side_width = self.calculate_side_width(cols); - let tab_shortcut = Text::new(" - select more panes").color_range(3, ..=4); - print_text_with_coordinates( - tab_shortcut, - side_width + 6, - rows.saturating_sub(2), - None, - None, - ); - }, - VisibilityAndFocus::BothSidesVisibleLeftSideFocused => { - let side_width = self.calculate_side_width(cols); - let tab_shortcut_text = " - browse selected panes"; - let tab_shortcut = Text::new(tab_shortcut_text).color_range(3, ..=4); - print_text_with_coordinates( - tab_shortcut, - side_width.saturating_sub(tab_shortcut_text.chars().count() + 1), - rows.saturating_sub(2), - None, - None, - ); - }, - VisibilityAndFocus::OnlyRightSideVisible => { - let tab_shortcut = Text::new(" - select more panes").color_range(3, ..=4); - print_text_with_coordinates(tab_shortcut, 4, rows.saturating_sub(2), None, None); - }, - VisibilityAndFocus::OnlyLeftSideVisible => { - // not visible - }, - }; - } - pub fn render_left_side(&self, rows: usize, cols: usize, is_focused: bool) { - let title_y = 0; - let left_side_base_x = 1; - let list_y = 2; - let side_width = self.calculate_side_width(cols); - let max_left_list_height = rows.saturating_sub(8); - let ( - extra_pane_count_on_top_left, - extra_pane_count_on_bottom_left, - extra_selected_item_count_on_top_left, - extra_selected_item_count_on_bottom_left, - left_side_panes, - ) = self.left_side_panes_list(side_width, max_left_list_height); - let (filter_prompt_text, filter_prompt) = self.filter_panes_prompt(); - let filter = self.filter(side_width.saturating_sub(filter_prompt_text.chars().count() + 1)); - let ( - _enter_select_panes_text, - enter_select_panes, - space_shortcut_text, - space_shortcut, - _escape_shortcut_text, - escape_shortcut, - ) = self.left_side_controls(side_width); - print_text_with_coordinates(filter_prompt, left_side_base_x, title_y, None, None); - if is_focused { - print_text_with_coordinates( - filter, - left_side_base_x + filter_prompt_text.chars().count(), - title_y, - None, - None, - ); - } - print_nested_list_with_coordinates( - left_side_panes.clone(), - left_side_base_x, - list_y, - Some(side_width), - None, - ); - if is_focused { - if let Some(marked_index) = self.marked_index.as_ref().map(|i| i.main_index) { - print_text_with_coordinates( - Text::new(">").color_range(3, ..).selected(), - left_side_base_x + 1, - (list_y + marked_index).saturating_sub(extra_pane_count_on_top_left), - None, - None, - ); - } - } - if extra_pane_count_on_top_left > 0 { - self.print_extra_pane_count( - extra_pane_count_on_top_left, - extra_selected_item_count_on_top_left, - list_y.saturating_sub(1), - left_side_base_x, - side_width, - ); - } - if extra_pane_count_on_bottom_left > 0 { - self.print_extra_pane_count( - extra_pane_count_on_bottom_left, - extra_selected_item_count_on_bottom_left, - list_y + left_side_panes.len(), - left_side_base_x, - side_width, - ); - } - if is_focused && !left_side_panes.is_empty() { - let controls_x = 1; - print_text_with_coordinates( - enter_select_panes, - controls_x, - list_y + left_side_panes.len() + 1, - None, - None, - ); - if self.marked_index.is_some() { - print_text_with_coordinates( - space_shortcut.clone(), - controls_x, - list_y + left_side_panes.len() + 2, - None, - None, - ); - print_text_with_coordinates( - escape_shortcut.clone(), - controls_x + space_shortcut_text.chars().count() + 1, - list_y + left_side_panes.len() + 2, - None, - None, - ); - } - } - } - pub fn render_right_side(&self, rows: usize, cols: usize, is_focused: bool) { - let side_width = self.calculate_side_width(cols); - let right_side_base_x = match self.visibility_and_focus { - VisibilityAndFocus::OnlyLeftSideVisible | VisibilityAndFocus::OnlyRightSideVisible => 1, - VisibilityAndFocus::BothSidesVisibleLeftSideFocused - | VisibilityAndFocus::BothSidesVisibleRightSideFocused => side_width + 4, - }; - let title_y = 0; - let list_y: usize = 2; - let max_right_list_height = rows.saturating_sub(11); - let selected_prompt = self.selected_panes_title(); - let ( - extra_pane_count_on_top_right, - extra_pane_count_on_bottom_right, - extra_selected_item_count_on_top_right, - extra_selected_item_count_on_bottom_right, - right_side_panes, - ) = self.right_side_panes_list(side_width, max_right_list_height); - let right_side_pane_count = right_side_panes.len(); - let ( - right_side_controls_1, - right_side_controls_2, - right_side_controls_3, - right_side_controls_4, - ) = self.right_side_controls(side_width); - if extra_pane_count_on_top_right > 0 { - self.print_extra_pane_count( - extra_pane_count_on_top_right, - extra_selected_item_count_on_top_right, - list_y.saturating_sub(1), - right_side_base_x, - side_width, - ); - } - if extra_pane_count_on_bottom_right > 0 { - self.print_extra_pane_count( - extra_pane_count_on_bottom_right, - extra_selected_item_count_on_bottom_right, - list_y + right_side_panes.len(), - right_side_base_x, - side_width, - ); - } - print_text_with_coordinates(selected_prompt, right_side_base_x + 3, title_y, None, None); - print_nested_list_with_coordinates( - right_side_panes, - right_side_base_x, - list_y, - Some(side_width), - None, - ); - if is_focused { - if let Some(marked_index) = self.marked_index.as_ref().map(|i| i.main_index) { - print_text_with_coordinates( - Text::new(">").color_range(3, ..).selected(), - right_side_base_x + 1, - (list_y + marked_index).saturating_sub(extra_pane_count_on_top_right), - None, - None, - ); - } - } - if is_focused && !self.right_side_panes.is_empty() { - print_text_with_coordinates( - right_side_controls_1, - right_side_base_x + 1, - list_y + right_side_pane_count + 1, - None, - None, - ); - print_text_with_coordinates( - right_side_controls_2, - right_side_base_x + 1, - list_y + right_side_pane_count + 3, - None, - None, - ); - print_text_with_coordinates( - right_side_controls_3, - right_side_base_x + 1, - list_y + right_side_pane_count + 4, - None, - None, - ); - print_text_with_coordinates( - right_side_controls_4, - right_side_base_x + 1, - list_y + right_side_pane_count + 5, - None, - None, - ); - } - } - pub fn render_help_line(&self, rows: usize, cols: usize) { - let help_line_text = match self.visibility_and_focus { - VisibilityAndFocus::OnlyLeftSideVisible => { - let full_help_line = "Help: Select one or more panes to group for bulk operations"; - let short_help_line = "Help: Select panes to group"; - if cols >= full_help_line.chars().count() { - full_help_line - } else { - short_help_line - } - }, - VisibilityAndFocus::OnlyRightSideVisible => { - let full_help_line = "Help: Perform bulk operations on all selected panes"; - let short_help_line = "Help: Perform bulk operations"; - if cols >= full_help_line.chars().count() { - full_help_line - } else { - short_help_line - } - }, - _ => { - let full_help_line = - "Help: Select panes on the left, then perform operations on the right."; - let short_help_line = "Help: Group panes for bulk operations"; - if cols >= full_help_line.chars().count() { - full_help_line - } else { - short_help_line - } - }, - }; - let help_line = Text::new(help_line_text); - print_text_with_coordinates(help_line, 0, rows, None, None); - } - pub fn render_focus_boundary(&self, rows: usize, cols: usize) { - let side_width = self.calculate_side_width(cols); - let x = match self.visibility_and_focus { - VisibilityAndFocus::OnlyRightSideVisible => 0, - VisibilityAndFocus::BothSidesVisibleLeftSideFocused - | VisibilityAndFocus::BothSidesVisibleRightSideFocused - | VisibilityAndFocus::OnlyLeftSideVisible => side_width + 2, - }; - let y = 0; - let height = rows.saturating_sub(2); - for i in y..=height { - if i == y && self.visibility_and_focus.left_side_is_focused() { - print_text_with_coordinates( - Text::new(TOP_RIGHT_CORNER_CHARACTER), - x, - i, - None, - None, - ); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x.saturating_sub(1), - i, - None, - None, - ); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x.saturating_sub(2), - i, - None, - None, - ); - } else if i == y && !self.visibility_and_focus.left_side_is_focused() { - print_text_with_coordinates(Text::new(TOP_LEFT_CORNER_CHARACTER), x, i, None, None); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x + 1, - i, - None, - None, - ); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x + 2, - i, - None, - None, - ); - } else if i == height && self.visibility_and_focus.left_side_is_focused() { - print_text_with_coordinates( - Text::new(BOTTOM_RIGHT_CORNER_CHARACTER), - x, - i, - None, - None, - ); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x.saturating_sub(1), - i, - None, - None, - ); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x.saturating_sub(2), - i, - None, - None, - ); - } else if i == height && !self.visibility_and_focus.left_side_is_focused() { - print_text_with_coordinates( - Text::new(BOTTOM_LEFT_CORNER_CHARACTER), - x, - i, - None, - None, - ); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x + 1, - i, - None, - None, - ); - print_text_with_coordinates( - Text::new(HORIZONTAL_BOUNDARY_CHARACTER), - x + 2, - i, - None, - None, - ); - } else { - print_text_with_coordinates(Text::new(BOUNDARY_CHARACTER), x, i, None, None); - } - } - } - pub fn calculate_side_width(&self, cols: usize) -> usize { - match self.visibility_and_focus { - VisibilityAndFocus::OnlyLeftSideVisible | VisibilityAndFocus::OnlyRightSideVisible => { - cols.saturating_sub(4) - }, - VisibilityAndFocus::BothSidesVisibleLeftSideFocused - | VisibilityAndFocus::BothSidesVisibleRightSideFocused => (cols / 2).saturating_sub(3), - } - } -} - -// ui components -impl App { - fn filter_panes_prompt(&self) -> (&'static str, Text) { - let search_prompt_text = if self.search_string.is_empty() { - "ALL PANES " - } else { - "FILTER: " - }; - let search_prompt = if self.visibility_and_focus.left_side_is_focused() { - Text::new(&search_prompt_text).color_range(2, ..) - } else { - Text::new(&search_prompt_text) - }; - (search_prompt_text, search_prompt) - } - fn filter(&self, max_width: usize) -> Text { - let search_string_text = if self.marked_index.is_none() && self.search_string.is_empty() { - let full = "[Type filter term...]"; - let short = "[...]"; - if max_width >= full.chars().count() { - full.to_owned() - } else { - short.to_owned() - } - } else if self.marked_index.is_none() && !self.search_string.is_empty() { - if max_width >= self.search_string.chars().count() + 1 { - format!("{}_", self.search_string) - } else { - let truncated: String = self - .search_string - .chars() - .rev() - .take(max_width.saturating_sub(4)) - .collect::>() - .iter() - .rev() - .collect(); - format!("...{}_", truncated) - } - } else if self.marked_index.is_some() && !self.search_string.is_empty() { - if max_width >= self.search_string.chars().count() { - format!("{}", self.search_string) - } else { - let truncated: String = self - .search_string - .chars() - .rev() - .take(max_width.saturating_sub(4)) - .collect::>() - .iter() - .rev() - .collect(); - format!("...{}", truncated) - } - } else { - format!("") - }; - Text::new(&search_string_text).color_range(3, ..) - } - fn left_side_panes_list( - &self, - max_width: usize, - max_list_height: usize, - ) -> (usize, usize, usize, usize, Vec) { - // returns: extra_pane_count_on_top, extra_pane_count_on_bottom, - // extra_selected_item_count_on_top, extra_selected_item_count_on_bottom, list - let mut left_side_panes = vec![]; - let pane_items_on_the_left = self - .search_results - .as_ref() - .unwrap_or_else(|| &self.left_side_panes); - let max_width_for_item = max_width.saturating_sub(3); // 3 for the list bulletin - let item_count = pane_items_on_the_left.iter().count(); - let first_item_index = if self.visibility_and_focus.left_side_is_focused() { - self.marked_index - .as_ref() - .map(|s| s.main_index.saturating_sub(max_list_height / 2)) - .unwrap_or(0) - } else { - 0 - }; - let last_item_index = std::cmp::min( - (max_list_height + first_item_index).saturating_sub(1), - item_count.saturating_sub(1), - ); - for (i, pane_item) in pane_items_on_the_left - .iter() - .enumerate() - .skip(first_item_index) - { - if i > last_item_index { - break; - } - let mut item = pane_item.render(max_width_for_item); - if Some(i) == self.marked_index.as_ref().map(|s| s.main_index) - && self.visibility_and_focus.left_side_is_focused() - { - item = item.selected(); - if self - .marked_index - .as_ref() - .map(|s| s.additional_indices.contains(&i)) - .unwrap_or(false) - { - item = item.selected().color_range(1, ..); - } - } else if self - .marked_index - .as_ref() - .map(|s| s.additional_indices.contains(&i)) - .unwrap_or(false) - && self.visibility_and_focus.left_side_is_focused() - { - item = item.selected(); - } - left_side_panes.push(item); - } - let extra_panes_on_top = first_item_index; - let extra_panes_on_bottom = item_count.saturating_sub(last_item_index + 1); - let extra_selected_item_count_on_top = if self.visibility_and_focus.left_side_is_focused() { - self.marked_index - .as_ref() - .map(|s| { - s.additional_indices - .iter() - .filter(|a| a < &&first_item_index) - .count() - }) - .unwrap_or(0) - } else { - 0 - }; - let extra_selected_item_count_on_bottom = - if self.visibility_and_focus.left_side_is_focused() { - self.marked_index - .as_ref() - .map(|s| { - s.additional_indices - .iter() - .filter(|a| a > &&last_item_index) - .count() - }) - .unwrap_or(0) - } else { - 0 - }; - ( - extra_panes_on_top, - extra_panes_on_bottom, - extra_selected_item_count_on_top, - extra_selected_item_count_on_bottom, - left_side_panes, - ) - } - fn left_side_controls( - &self, - max_width: usize, - ) -> (&'static str, Text, &'static str, Text, &'static str, Text) { - // returns three components and their text - let (enter_select_panes_text, enter_select_panes) = if self.marked_index.is_some() { - let enter_select_panes_text_full = " - select, <↓↑→> - navigate"; - let enter_select_panes_text_short = " / <↓↑→>..."; - if max_width >= enter_select_panes_text_full.chars().count() { - let enter_select_panes_full = Text::new(enter_select_panes_text_full) - .color_range(3, ..=6) - .color_range(3, 18..=22); - (enter_select_panes_text_full, enter_select_panes_full) - } else { - let enter_select_panes_short = Text::new(enter_select_panes_text_short) - .color_range(3, ..=6) - .color_range(3, 10..=14); - (enter_select_panes_text_short, enter_select_panes_short) - } - } else { - let enter_select_panes_text_full = " - select all, <↓↑> - navigate"; - let enter_select_panes_text_short = " / <↓↑>..."; - if max_width >= enter_select_panes_text_full.chars().count() { - let enter_select_panes_full = Text::new(enter_select_panes_text_full) - .color_range(3, ..=6) - .color_range(3, 21..=25); - (enter_select_panes_text_full, enter_select_panes_full) - } else { - let enter_select_panes_short = Text::new(enter_select_panes_text_short) - .color_range(3, ..=6) - .color_range(3, 10..=13); - (enter_select_panes_text_short, enter_select_panes_short) - } - }; - let space_shortcut_text_full = " - mark many,"; - let space_shortcut_text_short = " /"; - if self.marked_index.is_some() { - let escape_shortcut_text_full = " - remove marks"; - let escape_shortcut_text_short = "..."; - let (escape_shortcut, space_shortcut, escape_shortcut_text, space_shortcut_text) = - if max_width - >= space_shortcut_text_full.chars().count() - + escape_shortcut_text_full.chars().count() - { - ( - Text::new(escape_shortcut_text_full).color_range(3, ..=7), - Text::new(space_shortcut_text_full).color_range(3, ..=6), - escape_shortcut_text_full, - space_shortcut_text_full, - ) - } else { - ( - Text::new(escape_shortcut_text_short).color_range(3, ..=7), - Text::new(space_shortcut_text_short).color_range(3, ..=6), - escape_shortcut_text_short, - space_shortcut_text_short, - ) - }; - ( - enter_select_panes_text, - enter_select_panes, - space_shortcut_text, - space_shortcut, - escape_shortcut_text, - escape_shortcut, - ) - } else { - let escape_shortcut_text = if self.right_side_panes.is_empty() { - " - Close" - } else { - "" - }; - let escape_shortcut = Text::new(escape_shortcut_text).color_range(3, ..=7); - let space_shortcut = Text::new(space_shortcut_text_full).color_range(3, ..=6); - ( - enter_select_panes_text, - enter_select_panes, - space_shortcut_text_full, - space_shortcut, - escape_shortcut_text, - escape_shortcut, - ) - } - } - fn selected_panes_title(&self) -> Text { - let selected_prompt_text = "SELECTED PANES: "; - let selected_prompt = if self.visibility_and_focus.left_side_is_focused() { - Text::new(selected_prompt_text) - } else { - Text::new(selected_prompt_text).color_range(2, ..) - }; - selected_prompt - } - fn right_side_panes_list( - &self, - max_width: usize, - max_list_height: usize, - ) -> (usize, usize, usize, usize, Vec) { - // returns: extra_pane_count_on_top, extra_pane_count_on_bottom, - // extra_selected_item_count_on_top, extra_selected_item_count_on_bottom, list - let mut right_side_panes = vec![]; - let item_count = self.right_side_panes.iter().count(); - let first_item_index = if self.visibility_and_focus.left_side_is_focused() { - 0 - } else { - self.marked_index - .as_ref() - .map(|s| s.main_index.saturating_sub(max_list_height / 2)) - .unwrap_or(0) - }; - let last_item_index = std::cmp::min( - (max_list_height + first_item_index).saturating_sub(1), - item_count.saturating_sub(1), - ); - - let max_width_for_item = max_width.saturating_sub(3); // 3 for the list bulletin - for (i, pane_item) in self - .right_side_panes - .iter() - .enumerate() - .skip(first_item_index) - { - if i > last_item_index { - break; - } - let mut item = pane_item.render(max_width_for_item); - if &Some(i) == &self.marked_index.as_ref().map(|s| s.main_index) - && self.visibility_and_focus.right_side_is_focused() - { - item = item.selected(); - if self - .marked_index - .as_ref() - .map(|s| s.additional_indices.contains(&i)) - .unwrap_or(false) - { - item = item.selected().color_range(1, ..); - } - } else if self - .marked_index - .as_ref() - .map(|s| s.additional_indices.contains(&i)) - .unwrap_or(false) - && self.visibility_and_focus.right_side_is_focused() - { - item = item.selected(); - } - right_side_panes.push(item); - } - - let extra_panes_on_top = first_item_index; - let extra_panes_on_bottom = self - .right_side_panes - .iter() - .len() - .saturating_sub(last_item_index + 1); - let extra_selected_item_count_on_top = if self.visibility_and_focus.left_side_is_focused() { - 0 - } else { - self.marked_index - .as_ref() - .map(|s| { - s.additional_indices - .iter() - .filter(|a| a < &&first_item_index) - .count() - }) - .unwrap_or(0) - }; - let extra_selected_item_count_on_bottom = - if self.visibility_and_focus.left_side_is_focused() { - 0 - } else { - self.marked_index - .as_ref() - .map(|s| { - s.additional_indices - .iter() - .filter(|a| a > &&last_item_index) - .count() - }) - .unwrap_or(0) - }; - ( - extra_panes_on_top, - extra_panes_on_bottom, - extra_selected_item_count_on_top, - extra_selected_item_count_on_bottom, - right_side_panes, - ) - } - fn right_side_controls(&self, cols: usize) -> (Text, Text, Text, Text) { - let right_side_controls_text_1_full = "<←↓↑> - navigate, - clear"; - let right_side_controls_text_1_short = "<←↓↑>/..."; - let right_side_controls_1 = if cols >= right_side_controls_text_1_full.chars().count() { - Text::new(right_side_controls_text_1_full) - .color_range(3, ..=4) - .color_range(3, 18..=25) - } else { - Text::new(right_side_controls_text_1_short) - .color_range(3, ..=4) - .color_range(3, 6..=13) - }; - let right_side_controls_text_2_full = " - break out, - stack, - close"; - let right_side_controls_text_2_short = "//..."; - let right_side_controls_2 = if cols >= right_side_controls_text_2_full.chars().count() { - Text::new(right_side_controls_text_2_full) - .color_range(3, ..=2) - .color_range(3, 17..=19) - .color_range(3, 30..=32) - } else { - Text::new(right_side_controls_text_2_short) - .color_range(3, ..=2) - .color_range(3, 4..=6) - .color_range(3, 8..=10) - }; - let right_side_controls_text_3_full = " - break right, - break left"; - let right_side_controls_text_3_short = "/..."; - let right_side_controls_3 = if cols >= right_side_controls_text_3_full.chars().count() { - Text::new(right_side_controls_text_3_full) - .color_range(3, ..=2) - .color_range(3, 19..=21) - } else { - Text::new(right_side_controls_text_3_short) - .color_range(3, ..=2) - .color_range(3, 4..=6) - }; - let right_side_controls_text_4_full = " - embed, - float"; - let right_side_controls_text_4_short = "/..."; - let right_side_controls_4 = if cols >= right_side_controls_text_4_full.chars().count() { - Text::new(right_side_controls_text_4_full) - .color_range(3, ..=2) - .color_range(3, 13..=15) - } else { - Text::new(right_side_controls_text_4_short) - .color_range(3, ..=2) - .color_range(3, 4..=6) - }; - ( - right_side_controls_1, - right_side_controls_2, - right_side_controls_3, - right_side_controls_4, - ) - } - fn print_extra_pane_count( - &self, - count: usize, - selected_count: usize, - y: usize, - list_x: usize, - list_width: usize, - ) { - let extra_count_text = if selected_count > 0 { - format!("[+{} ({} selected)]", count, selected_count) - } else { - format!("[+{}]", count) - }; - let extra_count = Text::new(&extra_count_text).color_range(1, ..); - print_text_with_coordinates( - extra_count, - (list_x + list_width).saturating_sub(extra_count_text.chars().count()), - y, - None, - None, - ); - } -} diff --git a/default-plugins/status-bar/src/main.rs b/default-plugins/status-bar/src/main.rs index dd5d54c5..5bc54da0 100644 --- a/default-plugins/status-bar/src/main.rs +++ b/default-plugins/status-bar/src/main.rs @@ -39,8 +39,6 @@ struct State { display_system_clipboard_failure: bool, classic_ui: bool, base_mode_is_locked: bool, - own_client_id: Option, - grouped_panes_count: Option, } register_plugin!(State); @@ -199,7 +197,6 @@ impl ZellijPlugin for State { .get("classic") .map(|c| c == "true") .unwrap_or(false); - self.own_client_id = Some(get_plugin_ids().client_id); set_selectable(false); subscribe(&[ EventType::ModeUpdate, @@ -227,28 +224,6 @@ impl ZellijPlugin for State { } self.tabs = tabs; }, - Event::PaneUpdate(pane_manifest) => { - if let Some(own_client_id) = self.own_client_id { - let mut grouped_panes_count = 0; - for (_tab_index, pane_infos) in pane_manifest.panes { - for pane_info in pane_infos { - let is_in_pane_group = - pane_info.index_in_pane_group.get(&own_client_id).is_some(); - if is_in_pane_group { - grouped_panes_count += 1; - } - } - } - if Some(grouped_panes_count) != self.grouped_panes_count { - if grouped_panes_count == 0 { - self.grouped_panes_count = None; - } else { - self.grouped_panes_count = Some(grouped_panes_count); - } - should_render = true; - } - } - }, Event::CopyToClipboard(copy_destination) => { match self.text_copy_destination { Some(text_copy_destination) => { @@ -306,7 +281,6 @@ impl ZellijPlugin for State { self.base_mode_is_locked, self.text_copy_destination, self.display_system_clipboard_failure, - self.grouped_panes_count, ), fill_bg, ); diff --git a/default-plugins/status-bar/src/one_line_ui.rs b/default-plugins/status-bar/src/one_line_ui.rs index f6b88491..5abf67b6 100644 --- a/default-plugins/status-bar/src/one_line_ui.rs +++ b/default-plugins/status-bar/src/one_line_ui.rs @@ -6,7 +6,7 @@ use ansi_term::{ use std::collections::HashMap; use zellij_tile::prelude::actions::Action; use zellij_tile::prelude::*; -use zellij_tile_utils::{palette_match, style}; +use zellij_tile_utils::palette_match; use crate::first_line::{to_char, KeyAction, KeyMode, KeyShortcut}; use crate::second_line::{system_clipboard_error, text_copied_hint}; @@ -22,7 +22,6 @@ pub fn one_line_ui( base_mode_is_locked: bool, text_copied_to_clipboard_destination: Option, clipboard_failure: bool, - grouped_pane_count: Option, ) -> LinePart { if let Some(text_copied_to_clipboard_destination) = text_copied_to_clipboard_destination { return text_copied_hint(text_copied_to_clipboard_destination); @@ -36,18 +35,11 @@ pub fn one_line_ui( *max_len = max_len.saturating_sub(line_part.len); }; - let currently_marking_pane_group = help.currently_marking_pane_group.unwrap_or(false); render_mode_key_indicators(help, max_len, separator, base_mode_is_locked) .map(|mode_key_indicators| append(&mode_key_indicators, &mut max_len)) .and_then(|_| match help.mode { - InputMode::Normal | InputMode::Locked => match grouped_pane_count { - Some(grouped_pane_count) => { - render_group_controls(help, grouped_pane_count, max_len) - }, - None if currently_marking_pane_group => render_group_controls(help, 0, max_len), - None => render_secondary_info(help, tab_info, max_len), - } - .map(|secondary_info| append(&secondary_info, &mut max_len)), + InputMode::Normal | InputMode::Locked => render_secondary_info(help, tab_info, max_len) + .map(|secondary_info| append(&secondary_info, &mut max_len)), _ => add_keygroup_separator(help, max_len) .map(|key_group_separator| append(&key_group_separator, &mut max_len)) .and_then(|_| keybinds(help, max_len)) @@ -664,225 +656,6 @@ fn render_common_modifiers( line_part_to_render.len += prefix_text.chars().count() + separator.chars().count(); } -fn render_group_controls( - help: &ModeInfo, - grouped_pane_count: usize, - max_len: usize, -) -> Option { - let currently_marking_group = help.currently_marking_pane_group.unwrap_or(false); - let keymap = help.get_mode_keybinds(); - let (common_modifiers, multiple_select_key, pane_group_toggle_key, group_mark_toggle_key) = { - let multiple_select_key = multiple_select_key(&keymap); - let pane_group_toggle_key = single_action_key(&keymap, &[Action::TogglePaneInGroup]); - let group_mark_toggle_key = single_action_key(&keymap, &[Action::ToggleGroupMarking]); - let common_modifiers = get_common_modifiers( - vec![ - multiple_select_key.iter().next(), - pane_group_toggle_key.iter().next(), - group_mark_toggle_key.iter().next(), - ] - .into_iter() - .filter_map(|k| k) - .collect(), - ); - let multiple_select_key: Vec = multiple_select_key - .iter() - .map(|k| k.strip_common_modifiers(&common_modifiers)) - .collect(); - let pane_group_toggle_key: Vec = pane_group_toggle_key - .iter() - .map(|k| k.strip_common_modifiers(&common_modifiers)) - .collect(); - let group_mark_toggle_key: Vec = group_mark_toggle_key - .iter() - .map(|k| k.strip_common_modifiers(&common_modifiers)) - .collect(); - ( - common_modifiers, - multiple_select_key, - pane_group_toggle_key, - group_mark_toggle_key, - ) - }; - let multiple_select_key = multiple_select_key - .iter() - .next() - .map(|key| format!("{}", key)) - .unwrap_or("UNBOUND".to_owned()); - let pane_group_toggle_key = pane_group_toggle_key - .iter() - .next() - .map(|key| format!("{}", key)) - .unwrap_or("UNBOUND".to_owned()); - let group_mark_toggle_key = group_mark_toggle_key - .iter() - .next() - .map(|key| format!("{}", key)) - .unwrap_or("UNBOUND".to_owned()); - let background = help.style.colors.text_unselected.background; - let foreground = help.style.colors.text_unselected.base; - let superkey_prefix_style = style!(foreground, background).bold(); - let common_modifier_text = if common_modifiers.is_empty() { - "".to_owned() - } else { - format!( - "{} + ", - common_modifiers - .iter() - .map(|c| c.to_string()) - .collect::>() - .join("-") - ) - }; - - // full - let full_selected_panes_text = if common_modifier_text.is_empty() { - format!("{} SELECTED PANES", grouped_pane_count) - } else { - format!("{} SELECTED PANES |", grouped_pane_count) - }; - let full_group_actions_text = format!("<{}> Group Actions", &multiple_select_key); - let full_toggle_group_text = format!("<{}> Toggle Group", &pane_group_toggle_key); - let full_group_mark_toggle_text = format!("<{}> Follow Focus", &group_mark_toggle_key); - let ribbon_paddings_len = 12; - let full_controls_line_len = full_selected_panes_text.chars().count() - + 1 - + common_modifier_text.chars().count() - + full_group_actions_text.chars().count() - + full_toggle_group_text.chars().count() - + full_group_mark_toggle_text.chars().count() - + ribbon_paddings_len - + 1; // 1 for the end padding - - // medium - let medium_selected_panes_text = if common_modifier_text.is_empty() { - format!("{} SELECTED", grouped_pane_count) - } else { - format!("{} SELECTED |", grouped_pane_count) - }; - let medium_group_actions_text = format!("<{}> Actions", &multiple_select_key); - let medium_toggle_group_text = format!("<{}> Toggle", &pane_group_toggle_key); - let medium_group_mark_toggle_text = format!("<{}> Follow", &group_mark_toggle_key); - let ribbon_paddings_len = 12; - let medium_controls_line_len = medium_selected_panes_text.chars().count() - + 1 - + common_modifier_text.chars().count() - + medium_group_actions_text.chars().count() - + medium_toggle_group_text.chars().count() - + medium_group_mark_toggle_text.chars().count() - + ribbon_paddings_len - + 1; // 1 for the end padding - - // short - let short_selected_panes_text = if common_modifier_text.is_empty() { - format!("{} SELECTED", grouped_pane_count) - } else { - format!("{} SELECTED |", grouped_pane_count) - }; - let short_group_actions_text = format!("<{}>", &multiple_select_key); - let short_toggle_group_text = format!("<{}>", &pane_group_toggle_key); - let short_group_mark_toggle_text = format!("<{}>", &group_mark_toggle_key); - let color_emphasis_range_end = if common_modifier_text.is_empty() { - 0 - } else { - 2 - }; - let ribbon_paddings_len = 12; - let short_controls_line_len = short_selected_panes_text.chars().count() - + 1 - + common_modifier_text.chars().count() - + short_group_actions_text.chars().count() - + short_toggle_group_text.chars().count() - + short_group_mark_toggle_text.chars().count() - + ribbon_paddings_len - + 1; // 1 for the end padding - - let ( - selected_panes_text, - group_actions_text, - toggle_group_text, - group_mark_toggle_text, - controls_line_len, - ) = if max_len >= full_controls_line_len { - ( - full_selected_panes_text, - full_group_actions_text, - full_toggle_group_text, - full_group_mark_toggle_text, - full_controls_line_len, - ) - } else if max_len >= medium_controls_line_len { - ( - medium_selected_panes_text, - medium_group_actions_text, - medium_toggle_group_text, - medium_group_mark_toggle_text, - medium_controls_line_len, - ) - } else if max_len >= short_controls_line_len { - ( - short_selected_panes_text, - short_group_actions_text, - short_toggle_group_text, - short_group_mark_toggle_text, - short_controls_line_len, - ) - } else { - return None; - }; - let selected_panes = serialize_text( - &Text::new(&selected_panes_text) - .color_range( - 3, - ..selected_panes_text - .chars() - .count() - .saturating_sub(color_emphasis_range_end), - ) - .opaque(), - ); - let group_actions_ribbon = serialize_ribbon( - &Text::new(&group_actions_text).color_range(0, 1..=multiple_select_key.chars().count()), - ); - let toggle_group_ribbon = serialize_ribbon( - &Text::new(&toggle_group_text).color_range(0, 1..=pane_group_toggle_key.chars().count()), - ); - let mut group_mark_toggle_ribbon = Text::new(&group_mark_toggle_text) - .color_range(0, 1..=group_mark_toggle_key.chars().count()); - if currently_marking_group { - group_mark_toggle_ribbon = group_mark_toggle_ribbon.selected(); - } - let group_mark_toggle_ribbon = serialize_ribbon(&group_mark_toggle_ribbon); - let controls_line = if common_modifiers.is_empty() { - format!( - "{} {}{}{}", - selected_panes, group_actions_ribbon, toggle_group_ribbon, group_mark_toggle_ribbon - ) - } else { - let common_modifier = - serialize_text(&Text::new(&common_modifier_text).color_range(0, ..).opaque()); - format!( - "{} {}{}{}{}", - selected_panes, - common_modifier, - group_actions_ribbon, - toggle_group_ribbon, - group_mark_toggle_ribbon - ) - }; - let remaining_space = max_len.saturating_sub(controls_line_len); - let mut padding = String::new(); - let mut padding_len = 0; - for _ in 0..remaining_space { - padding.push_str(&ANSIStrings(&[superkey_prefix_style.paint(" ")]).to_string()); - padding_len += 1; - } - Some(LinePart { - part: format!("{}{}", padding, controls_line), - len: controls_line_len + padding_len, - }) -} - fn render_secondary_info( help: &ModeInfo, tab_info: Option<&TabInfo>, @@ -1745,25 +1518,6 @@ fn configuration_key(keymap: &[(KeyWithModifier, Vec)]) -> Vec)]) -> Vec { - let mut matching = keymap.iter().find_map(|(key, acvec)| { - let has_match = acvec - .iter() - .find(|a| a.launches_plugin("zellij:multiple-select")) // TODO: make this an alias - .is_some(); - if has_match { - Some(key.clone()) - } else { - None - } - }); - if let Some(matching) = matching.take() { - vec![matching] - } else { - vec![] - } -} - fn style_key_with_modifier(keyvec: &[KeyWithModifier], color_index: Option) -> LinePart { if keyvec.is_empty() { return LinePart::default(); diff --git a/example/config.kdl b/example/config.kdl index 92fbda49..44f56a8f 100644 --- a/example/config.kdl +++ b/example/config.kdl @@ -138,12 +138,6 @@ keybinds { bind "Alt k" "Alt Up" { MoveFocus "Up"; } bind "Alt =" "Alt +" { Resize "Increase"; } bind "Alt -" { Resize "Decrease"; } - bind "Alt m" { - LaunchOrFocusPlugin "zellij:multiple-select" { - floating true - move_to_focused_tab true - } - } bind "Alt p" { TogglePaneInGroup; } bind "Alt Shift p" { ToggleGroupMarking; } } diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index cc551273..3e89ea65 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -5,6 +5,7 @@ pub mod tab; mod background_jobs; mod logging_pipe; +mod pane_groups; mod plugins; mod pty; mod pty_writer; diff --git a/zellij-server/src/pane_groups.rs b/zellij-server/src/pane_groups.rs new file mode 100644 index 00000000..6cf68eed --- /dev/null +++ b/zellij-server/src/pane_groups.rs @@ -0,0 +1,469 @@ +use std::collections::{HashMap, HashSet}; + +use zellij_utils::data::FloatingPaneCoordinates; +use zellij_utils::input::layout::{RunPluginOrAlias, SplitSize}; +use zellij_utils::pane_size::Size; + +use crate::{panes::PaneId, pty::PtyInstruction, thread_bus::ThreadSenders, ClientId}; + +pub struct PaneGroups { + panes_in_group: HashMap>, + senders: ThreadSenders, +} + +impl std::fmt::Debug for PaneGroups { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PaneGroups") + .field("panes_in_group", &self.panes_in_group) + .finish_non_exhaustive() + } +} + +impl PaneGroups { + pub fn new(senders: ThreadSenders) -> Self { + PaneGroups { + panes_in_group: HashMap::new(), + senders, + } + } + pub fn clone_inner(&self) -> HashMap> { + self.panes_in_group.clone() + } + pub fn get_client_pane_group(&self, client_id: &ClientId) -> HashSet { + self.panes_in_group + .get(client_id) + .map(|p| p.iter().copied().collect()) + .unwrap_or_else(|| HashSet::new()) + } + pub fn clear_pane_group(&mut self, client_id: &ClientId) { + self.panes_in_group.get_mut(client_id).map(|p| p.clear()); + } + pub fn toggle_pane_id_in_group( + &mut self, + pane_id: PaneId, + screen_size: Size, + client_id: &ClientId, + ) { + let previous_groups = self.clone_inner(); + let client_pane_group = self + .panes_in_group + .entry(*client_id) + .or_insert_with(|| vec![]); + if client_pane_group.contains(&pane_id) { + client_pane_group.retain(|p| p != &pane_id); + } else { + client_pane_group.push(pane_id); + }; + if self.should_launch_plugin(&previous_groups, client_id) { + self.launch_plugin(screen_size, client_id); + } + } + pub fn add_pane_id_to_group( + &mut self, + pane_id: PaneId, + screen_size: Size, + client_id: &ClientId, + ) { + let previous_groups = self.clone_inner(); + let client_pane_group = self + .panes_in_group + .entry(*client_id) + .or_insert_with(|| vec![]); + if !client_pane_group.contains(&pane_id) { + client_pane_group.push(pane_id); + } + if self.should_launch_plugin(&previous_groups, client_id) { + self.launch_plugin(screen_size, client_id); + } + } + pub fn group_and_ungroup_panes( + &mut self, + mut pane_ids_to_group: Vec, + pane_ids_to_ungroup: Vec, + screen_size: Size, + client_id: &ClientId, + ) { + let previous_groups = self.clone_inner(); + let client_pane_group = self + .panes_in_group + .entry(*client_id) + .or_insert_with(|| vec![]); + client_pane_group.append(&mut pane_ids_to_group); + client_pane_group.retain(|p| !pane_ids_to_ungroup.contains(p)); + if self.should_launch_plugin(&previous_groups, client_id) { + self.launch_plugin(screen_size, client_id); + } + } + pub fn override_groups_with(&mut self, new_pane_groups: HashMap>) { + self.panes_in_group = new_pane_groups; + } + fn should_launch_plugin( + &self, + previous_groups: &HashMap>, + client_id: &ClientId, + ) -> bool { + let mut should_launch = false; + for (client_id, previous_panes) in previous_groups { + let previous_panes_has_panes = !previous_panes.is_empty(); + let current_panes_has_panes = self + .panes_in_group + .get(&client_id) + .map(|g| !g.is_empty()) + .unwrap_or(false); + if !previous_panes_has_panes && current_panes_has_panes { + should_launch = true; + } + } + should_launch || previous_groups.get(&client_id).is_none() + } + fn launch_plugin(&self, screen_size: Size, client_id: &ClientId) { + if let Ok(run_plugin) = + RunPluginOrAlias::from_url("zellij:multiple-select", &None, None, None) + { + let tab_index = 1; + let size = Size::default(); + let should_float = Some(true); + let should_be_opened_in_place = false; + let pane_title = None; + let skip_cache = false; + let cwd = None; + let should_focus_plugin = Some(false); + let width_30_percent = (screen_size.cols as f64 * 0.3) as usize; + let height_30_percent = (screen_size.rows as f64 * 0.3) as usize; + let width = std::cmp::max(width_30_percent, 48); + let height = std::cmp::max(height_30_percent, 10); + let y_position = screen_size.rows.saturating_sub(height + 2); + let floating_pane_coordinates = FloatingPaneCoordinates { + x: Some(SplitSize::Fixed(2)), + y: Some(SplitSize::Fixed(y_position)), + width: Some(SplitSize::Fixed(width)), + height: Some(SplitSize::Fixed(height)), + pinned: Some(true), + }; + let _ = self.senders.send_to_pty(PtyInstruction::FillPluginCwd( + should_float, + should_be_opened_in_place, + pane_title, + run_plugin, + tab_index, + None, + *client_id, + size, + skip_cache, + cwd, + should_focus_plugin, + Some(floating_pane_coordinates), + )); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::collections::HashMap; + + fn create_mock_senders() -> ThreadSenders { + let mut mock = ThreadSenders::default(); + mock.should_silently_fail = true; + mock + } + + fn create_test_pane_groups() -> PaneGroups { + PaneGroups::new(create_mock_senders()) + } + + fn create_test_screen_size() -> Size { + Size { rows: 24, cols: 80 } + } + + #[test] + fn new_creates_empty_pane_groups() { + let pane_groups = create_test_pane_groups(); + assert!(pane_groups.panes_in_group.is_empty()); + } + + #[test] + fn clone_inner_returns_copy_of_internal_map() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let pane_id = PaneId::Terminal(10); + let screen_size = create_test_screen_size(); + + pane_groups.add_pane_id_to_group(pane_id, screen_size, &client_id); + let cloned = pane_groups.clone_inner(); + + assert_eq!(cloned.len(), 1); + assert!(cloned.contains_key(&client_id)); + assert_eq!(cloned[&client_id], vec![pane_id]); + } + + #[test] + fn get_client_pane_group_returns_empty_set_for_nonexistent_client() { + let pane_groups = create_test_pane_groups(); + let client_id: ClientId = 999; + + let result = pane_groups.get_client_pane_group(&client_id); + assert!(result.is_empty()); + } + + #[test] + fn get_client_pane_group_returns_correct_panes() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let pane_ids = vec![ + PaneId::Terminal(10), + PaneId::Plugin(20), + PaneId::Terminal(30), + ]; + let screen_size = create_test_screen_size(); + + for pane_id in &pane_ids { + pane_groups.add_pane_id_to_group(*pane_id, screen_size, &client_id); + } + + let result = pane_groups.get_client_pane_group(&client_id); + assert_eq!(result.len(), 3); + for pane_id in pane_ids { + assert!(result.contains(&pane_id)); + } + } + + #[test] + fn clear_pane_group_clears_existing_group() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let pane_ids = vec![ + PaneId::Terminal(10), + PaneId::Plugin(20), + PaneId::Terminal(30), + ]; + let screen_size = create_test_screen_size(); + + for pane_id in pane_ids { + pane_groups.add_pane_id_to_group(pane_id, screen_size, &client_id); + } + + assert!(!pane_groups.get_client_pane_group(&client_id).is_empty()); + + pane_groups.clear_pane_group(&client_id); + + assert!(pane_groups.get_client_pane_group(&client_id).is_empty()); + } + + #[test] + fn clear_pane_group_handles_nonexistent_client() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 999; + + pane_groups.clear_pane_group(&client_id); + assert!(pane_groups.get_client_pane_group(&client_id).is_empty()); + } + + #[test] + fn toggle_pane_id_adds_new_pane() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let pane_id = PaneId::Terminal(10); + let screen_size = create_test_screen_size(); + + pane_groups.toggle_pane_id_in_group(pane_id, screen_size, &client_id); + + let result = pane_groups.get_client_pane_group(&client_id); + assert!(result.contains(&pane_id)); + } + + #[test] + fn toggle_pane_id_removes_existing_pane() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let pane_id = PaneId::Plugin(10); + let screen_size = create_test_screen_size(); + + pane_groups.add_pane_id_to_group(pane_id, screen_size, &client_id); + assert!(pane_groups + .get_client_pane_group(&client_id) + .contains(&pane_id)); + + pane_groups.toggle_pane_id_in_group(pane_id, screen_size, &client_id); + assert!(!pane_groups + .get_client_pane_group(&client_id) + .contains(&pane_id)); + } + + #[test] + fn add_pane_id_to_group_adds_new_pane() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let pane_id = PaneId::Terminal(10); + let screen_size = create_test_screen_size(); + + pane_groups.add_pane_id_to_group(pane_id, screen_size, &client_id); + + let result = pane_groups.get_client_pane_group(&client_id); + assert!(result.contains(&pane_id)); + } + + #[test] + fn add_pane_id_to_group_does_not_duplicate() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let pane_id = PaneId::Plugin(10); + let screen_size = create_test_screen_size(); + + pane_groups.add_pane_id_to_group(pane_id, screen_size, &client_id); + pane_groups.add_pane_id_to_group(pane_id, screen_size, &client_id); + + let result = pane_groups.get_client_pane_group(&client_id); + assert_eq!(result.len(), 1); + assert!(result.contains(&pane_id)); + } + + #[test] + fn group_and_ungroup_panes_adds_and_removes_correctly() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let screen_size = create_test_screen_size(); + + let initial_panes = vec![PaneId::Terminal(1), PaneId::Plugin(2), PaneId::Terminal(3)]; + for pane_id in &initial_panes { + pane_groups.add_pane_id_to_group(*pane_id, screen_size, &client_id); + } + + let panes_to_add = vec![PaneId::Plugin(4), PaneId::Terminal(5)]; + let panes_to_remove = vec![PaneId::Plugin(2), PaneId::Terminal(3)]; + + pane_groups.group_and_ungroup_panes(panes_to_add, panes_to_remove, screen_size, &client_id); + + let result = pane_groups.get_client_pane_group(&client_id); + + assert!(result.contains(&PaneId::Terminal(1))); + assert!(result.contains(&PaneId::Plugin(4))); + assert!(result.contains(&PaneId::Terminal(5))); + assert!(!result.contains(&PaneId::Plugin(2))); + assert!(!result.contains(&PaneId::Terminal(3))); + assert_eq!(result.len(), 3); + } + + #[test] + fn override_groups_with_replaces_all_groups() { + let mut pane_groups = create_test_pane_groups(); + let client_id1: ClientId = 1; + let client_id2: ClientId = 2; + let screen_size = create_test_screen_size(); + + pane_groups.add_pane_id_to_group(PaneId::Terminal(10), screen_size, &client_id1); + + let mut new_groups = HashMap::new(); + new_groups.insert(client_id2, vec![PaneId::Plugin(20), PaneId::Terminal(30)]); + + pane_groups.override_groups_with(new_groups); + + assert!(pane_groups.get_client_pane_group(&client_id1).is_empty()); + + let result = pane_groups.get_client_pane_group(&client_id2); + assert!(result.contains(&PaneId::Plugin(20))); + assert!(result.contains(&PaneId::Terminal(30))); + assert_eq!(result.len(), 2); + } + + #[test] + fn multiple_clients_independent_groups() { + let mut pane_groups = create_test_pane_groups(); + let client_id1: ClientId = 1; + let client_id2: ClientId = 2; + let screen_size = create_test_screen_size(); + + pane_groups.add_pane_id_to_group(PaneId::Terminal(10), screen_size, &client_id1); + pane_groups.add_pane_id_to_group(PaneId::Plugin(20), screen_size, &client_id2); + + let group1 = pane_groups.get_client_pane_group(&client_id1); + let group2 = pane_groups.get_client_pane_group(&client_id2); + + assert!(group1.contains(&PaneId::Terminal(10))); + assert!(!group1.contains(&PaneId::Plugin(20))); + + assert!(group2.contains(&PaneId::Plugin(20))); + assert!(!group2.contains(&PaneId::Terminal(10))); + } + + #[test] + fn pane_id_variants_work_correctly() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let screen_size = create_test_screen_size(); + + let terminal_pane = PaneId::Terminal(100); + let plugin_pane = PaneId::Plugin(200); + + pane_groups.add_pane_id_to_group(terminal_pane, screen_size, &client_id); + pane_groups.add_pane_id_to_group(plugin_pane, screen_size, &client_id); + + let result = pane_groups.get_client_pane_group(&client_id); + assert!(result.contains(&terminal_pane)); + assert!(result.contains(&plugin_pane)); + assert_eq!(result.len(), 2); + + let another_terminal = PaneId::Terminal(200); + assert!(!result.contains(&another_terminal)); + } + + #[test] + fn should_launch_plugin_returns_true_when_first_pane_added() { + let pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let previous_groups = HashMap::new(); + + assert!(pane_groups.should_launch_plugin(&previous_groups, &client_id)); + } + + #[test] + fn should_launch_plugin_returns_true_when_empty_to_non_empty() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let screen_size = create_test_screen_size(); + + let mut previous_groups = HashMap::new(); + previous_groups.insert(client_id, vec![]); + + pane_groups.add_pane_id_to_group(PaneId::Terminal(10), screen_size, &client_id); + + assert!(pane_groups.should_launch_plugin(&previous_groups, &client_id)); + } + + #[test] + fn should_launch_plugin_returns_false_when_non_empty_to_non_empty() { + let mut pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + let screen_size = create_test_screen_size(); + + pane_groups.add_pane_id_to_group(PaneId::Terminal(10), screen_size, &client_id); + let previous_groups = pane_groups.clone_inner(); + + pane_groups.add_pane_id_to_group(PaneId::Plugin(20), screen_size, &client_id); + + assert!(!pane_groups.should_launch_plugin(&previous_groups, &client_id)); + } + + #[test] + fn should_launch_plugin_returns_false_when_non_empty_to_empty() { + let pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + + let mut previous_groups = HashMap::new(); + previous_groups.insert(client_id, vec![PaneId::Terminal(10)]); + + assert!(!pane_groups.should_launch_plugin(&previous_groups, &client_id)); + } + + #[test] + fn should_launch_plugin_returns_false_when_empty_to_empty() { + let pane_groups = create_test_pane_groups(); + let client_id: ClientId = 1; + + let mut previous_groups = HashMap::new(); + previous_groups.insert(client_id, vec![]); + + assert!(!pane_groups.should_launch_plugin(&previous_groups, &client_id)); + } +} diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs index 4913ee51..e360b642 100644 --- a/zellij-server/src/panes/floating_panes/mod.rs +++ b/zellij-server/src/panes/floating_panes/mod.rs @@ -316,6 +316,20 @@ impl FloatingPanes { pub fn last_floating_pane_id(&self) -> Option { self.panes.keys().last().copied() } + pub fn last_selectable_floating_pane_id(&self) -> Option { + self.panes + .iter() + .filter(|(_p_id, p)| p.selectable()) + .last() + .map(|(p_id, _p)| *p_id) + } + pub fn has_selectable_panes(&self) -> bool { + self.panes + .iter() + .filter(|(_p_id, p)| p.selectable()) + .last() + .is_some() + } pub fn first_active_floating_pane_id(&self) -> Option { self.active_panes.values().next().copied() } @@ -388,6 +402,7 @@ impl FloatingPanes { let multiple_users_exist_in_session = { self.connected_clients_in_app.borrow().len() > 1 }; active_panes.retain(|c_id, _| self.connected_clients.borrow().contains(c_id)); + let pane_is_selectable = pane.selectable(); let mut pane_contents_and_ui = PaneContentsAndUi::new( pane, output, @@ -415,6 +430,7 @@ impl FloatingPanes { client_mode, self.session_is_mirrored, is_floating, + pane_is_selectable, ) .with_context(err_context)?; if let PaneId::Plugin(..) = kind { diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index 9ec50fb0..be8bdb6e 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -967,6 +967,7 @@ impl TiledPanes { let pane_is_stacked = pane.current_geom().is_stacked(); let pane_is_one_liner_in_stack = pane_is_stacked && pane.current_geom().rows.is_fixed(); + let pane_is_selectable = pane.selectable(); let mut pane_contents_and_ui = PaneContentsAndUi::new( pane, output, @@ -1004,6 +1005,7 @@ impl TiledPanes { client_mode, self.session_is_mirrored, is_floating, + pane_is_selectable, ) .with_context(err_context)?; } else if pane_is_stacked { @@ -1015,6 +1017,7 @@ impl TiledPanes { client_mode, self.session_is_mirrored, is_floating, + pane_is_selectable, ) .with_context(err_context)?; // we also need to render its boundaries as normal diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index d7cb07d2..ec13df38 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -25,8 +25,8 @@ use wasm_bridge::WasmBridge; use async_std::{channel, future::timeout, task}; use zellij_utils::{ data::{ - ClientInfo, Event, EventType, InputMode, MessageToPlugin, PermissionStatus, PermissionType, - PipeMessage, PipeSource, PluginCapabilities, + ClientInfo, Event, EventType, FloatingPaneCoordinates, InputMode, MessageToPlugin, + PermissionStatus, PermissionType, PipeMessage, PipeSource, PluginCapabilities, }, errors::{prelude::*, ContextType, PluginContext}, input::{ @@ -55,6 +55,8 @@ pub enum PluginInstruction { Size, Option, // cwd bool, // skip cache + Option, // should focus plugin + Option, ), LoadBackgroundPlugin(RunPluginOrAlias, ClientId), Update(Vec<(Option, Option, Event)>), // Focused plugin / broadcast, client_id, event data @@ -281,6 +283,8 @@ pub(crate) fn plugin_thread_main( size, cwd, skip_cache, + should_focus_plugin, + floating_pane_coordinates, ) => { run_plugin_or_alias.populate_run_plugin_if_needed(&plugin_aliases); let cwd = run_plugin_or_alias.get_initial_cwd().or(cwd); @@ -306,6 +310,8 @@ pub(crate) fn plugin_thread_main( pane_id_to_replace, cwd, start_suppressed, + floating_pane_coordinates, + should_focus_plugin, Some(client_id), ))); }, @@ -378,6 +384,8 @@ pub(crate) fn plugin_thread_main( None, start_suppressed, None, + None, + None, ), )); }, @@ -1070,7 +1078,8 @@ fn load_background_plugin( pane_id_to_replace, cwd, start_suppressed, - // None, + None, + None, Some(client_id), ))); }, diff --git a/zellij-server/src/plugins/plugin_loader.rs b/zellij-server/src/plugins/plugin_loader.rs index 1dbe020e..4d8a4542 100644 --- a/zellij-server/src/plugins/plugin_loader.rs +++ b/zellij-server/src/plugins/plugin_loader.rs @@ -868,6 +868,7 @@ impl<'a> PluginLoader<'a> { default_mode: self.default_mode.clone(), subscriptions: Arc::new(Mutex::new(HashSet::new())), keybinds: self.keybinds.clone(), + intercepting_key_presses: false, stdin_pipe, stdout_pipe, }; diff --git a/zellij-server/src/plugins/plugin_map.rs b/zellij-server/src/plugins/plugin_map.rs index 62020f4c..a92c291a 100644 --- a/zellij-server/src/plugins/plugin_map.rs +++ b/zellij-server/src/plugins/plugin_map.rs @@ -313,6 +313,7 @@ pub struct PluginEnv { pub stdin_pipe: Arc>>, pub stdout_pipe: Arc>>, pub keybinds: Keybinds, + pub intercepting_key_presses: bool, } #[derive(Clone)] @@ -457,4 +458,7 @@ impl RunningPlugin { pub fn update_default_shell(&mut self, default_shell: Option) { self.store.data_mut().default_shell = default_shell; } + pub fn intercepting_key_presses(&self) -> bool { + self.store.data().intercepting_key_presses + } } diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index 60f850cc..276461d9 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -714,6 +714,8 @@ pub fn load_new_plugin_from_hd() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -794,6 +796,8 @@ pub fn load_new_plugin_with_plugin_alias() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -870,6 +874,8 @@ pub fn plugin_workers() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); // we send a SystemClipboardFailure to trigger the custom handler in the fixture plugin that @@ -950,6 +956,8 @@ pub fn plugin_workers_persist_state() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); // we send a SystemClipboardFailure to trigger the custom handler in the fixture plugin that @@ -1040,6 +1048,8 @@ pub fn can_subscribe_to_hd_events() { size, None, false, + None, + None, )); // extra long time because we only start the fs watcher on plugin load std::thread::sleep(std::time::Duration::from_millis(5000)); @@ -1118,6 +1128,8 @@ pub fn switch_to_mode_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1190,6 +1202,8 @@ pub fn switch_to_mode_plugin_command_permission_denied() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1262,6 +1276,8 @@ pub fn new_tabs_with_layout_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1348,6 +1364,8 @@ pub fn new_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1420,6 +1438,8 @@ pub fn go_to_next_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1491,6 +1511,8 @@ pub fn go_to_previous_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1562,6 +1584,8 @@ pub fn resize_focused_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1633,6 +1657,8 @@ pub fn resize_focused_pane_with_direction_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1704,6 +1730,8 @@ pub fn focus_next_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1775,6 +1803,8 @@ pub fn focus_previous_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1846,6 +1876,8 @@ pub fn move_focus_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1917,6 +1949,8 @@ pub fn move_focus_or_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -1988,6 +2022,8 @@ pub fn edit_scrollback_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2059,6 +2095,8 @@ pub fn write_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2130,6 +2168,8 @@ pub fn write_chars_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2201,6 +2241,8 @@ pub fn toggle_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2272,6 +2314,8 @@ pub fn move_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2343,6 +2387,8 @@ pub fn move_pane_with_direction_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2415,6 +2461,8 @@ pub fn clear_screen_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2487,6 +2535,8 @@ pub fn scroll_up_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2558,6 +2608,8 @@ pub fn scroll_down_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2629,6 +2681,8 @@ pub fn scroll_to_top_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2700,6 +2754,8 @@ pub fn scroll_to_bottom_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2771,6 +2827,8 @@ pub fn page_scroll_up_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2842,6 +2900,8 @@ pub fn page_scroll_down_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2913,6 +2973,8 @@ pub fn toggle_focus_fullscreen_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -2984,6 +3046,8 @@ pub fn toggle_pane_frames_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3055,6 +3119,8 @@ pub fn toggle_pane_embed_or_eject_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3126,6 +3192,8 @@ pub fn undo_rename_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3197,6 +3265,8 @@ pub fn close_focus_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3268,6 +3338,8 @@ pub fn toggle_active_tab_sync_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3339,6 +3411,8 @@ pub fn close_focused_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3410,6 +3484,8 @@ pub fn undo_rename_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3481,6 +3557,8 @@ pub fn previous_swap_layout_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3552,6 +3630,8 @@ pub fn next_swap_layout_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3623,6 +3703,8 @@ pub fn go_to_tab_name_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3694,6 +3776,8 @@ pub fn focus_or_create_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3765,6 +3849,8 @@ pub fn go_to_tab() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3836,6 +3922,8 @@ pub fn start_or_reload_plugin() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3914,6 +4002,8 @@ pub fn quit_zellij_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -3992,6 +4082,8 @@ pub fn detach_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4070,6 +4162,8 @@ pub fn open_file_floating_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4152,6 +4246,8 @@ pub fn open_file_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4235,6 +4331,8 @@ pub fn open_file_with_line_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4317,6 +4415,8 @@ pub fn open_file_with_line_floating_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4399,6 +4499,8 @@ pub fn open_terminal_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4477,6 +4579,8 @@ pub fn open_terminal_floating_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4555,6 +4659,8 @@ pub fn open_command_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4633,6 +4739,8 @@ pub fn open_command_pane_floating_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4704,6 +4812,8 @@ pub fn switch_to_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4775,6 +4885,8 @@ pub fn hide_self_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4845,6 +4957,8 @@ pub fn show_self_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4916,6 +5030,8 @@ pub fn close_terminal_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -4987,6 +5103,8 @@ pub fn close_plugin_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5058,6 +5176,8 @@ pub fn focus_terminal_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5129,6 +5249,8 @@ pub fn focus_plugin_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5200,6 +5322,8 @@ pub fn rename_terminal_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5271,6 +5395,8 @@ pub fn rename_plugin_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5342,6 +5468,8 @@ pub fn rename_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5422,6 +5550,8 @@ pub fn send_configuration_to_plugins() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5490,6 +5620,8 @@ pub fn request_plugin_permissions() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5582,6 +5714,8 @@ pub fn granted_permission_request_result() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5673,6 +5807,8 @@ pub fn denied_permission_request_result() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5744,6 +5880,8 @@ pub fn run_command_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5822,6 +5960,8 @@ pub fn run_command_with_env_vars_and_cwd_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5900,6 +6040,8 @@ pub fn web_request_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -5971,6 +6113,8 @@ pub fn unblock_input_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6053,6 +6197,8 @@ pub fn block_input_plugin_command() { size, None, false, + None, + None, )); // extra long time because we only start the fs watcher on plugin load std::thread::sleep(std::time::Duration::from_millis(5000)); @@ -6143,6 +6289,8 @@ pub fn pipe_output_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6226,6 +6374,8 @@ pub fn pipe_message_to_plugin_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::CliPipe { @@ -6320,6 +6470,8 @@ pub fn switch_session_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6401,6 +6553,8 @@ pub fn switch_session_with_layout_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6482,6 +6636,8 @@ pub fn switch_session_with_layout_and_cwd_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6563,6 +6719,8 @@ pub fn disconnect_other_clients_plugins_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6644,6 +6802,8 @@ pub fn reconfigure_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6729,6 +6889,8 @@ pub fn run_plugin_in_specific_cwd() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -6803,6 +6965,8 @@ pub fn hide_pane_with_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -6874,6 +7038,8 @@ pub fn show_pane_with_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -6952,6 +7118,8 @@ pub fn open_command_pane_background_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7027,6 +7195,8 @@ pub fn rerun_command_pane_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7098,6 +7268,8 @@ pub fn resize_pane_with_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7169,6 +7341,8 @@ pub fn edit_scrollback_for_pane_with_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7240,6 +7414,8 @@ pub fn write_to_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7311,6 +7487,8 @@ pub fn write_chars_to_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7382,6 +7560,8 @@ pub fn move_pane_with_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7453,6 +7633,8 @@ pub fn move_pane_with_pane_id_in_direction_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7524,6 +7706,8 @@ pub fn clear_screen_for_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7595,6 +7779,8 @@ pub fn scroll_up_in_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7666,6 +7852,8 @@ pub fn scroll_down_in_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7737,6 +7925,8 @@ pub fn scroll_to_top_in_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7808,6 +7998,8 @@ pub fn scroll_to_bottom_in_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7879,6 +8071,8 @@ pub fn page_scroll_up_in_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -7950,6 +8144,8 @@ pub fn page_scroll_down_in_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8021,6 +8217,8 @@ pub fn toggle_pane_id_fullscreen_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8092,6 +8290,8 @@ pub fn toggle_pane_embed_or_eject_for_pane_id_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8163,6 +8363,8 @@ pub fn close_tab_with_index_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8234,6 +8436,8 @@ pub fn break_panes_to_new_tab_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8305,6 +8509,8 @@ pub fn break_panes_to_tab_with_index_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8376,6 +8582,8 @@ pub fn reload_plugin_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8447,6 +8655,8 @@ pub fn load_new_plugin_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8525,6 +8735,8 @@ pub fn rebind_keys_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); @@ -8599,6 +8811,8 @@ pub fn list_clients_plugin_command() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(500)); let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( @@ -8670,6 +8884,8 @@ pub fn before_close_plugin_event() { size, None, false, + None, + None, )); std::thread::sleep(std::time::Duration::from_millis(5000)); // here we send an unload to plugin id 0 (the first plugin id, presumably this plugin) diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs index d01a24e7..00b30aa1 100644 --- a/zellij-server/src/plugins/wasm_bridge.rs +++ b/zellij-server/src/plugins/wasm_bridge.rs @@ -324,6 +324,15 @@ impl WasmBridge { for (_worker_name, worker_sender) in workers { drop(worker_sender.send(MessageToWorker::Exit)); } + { + // if the plugin was intercepting key presses and for some reason did not clear + // this state, we make sure to do it ourselves so that the user will not get stuck + if running_plugin.lock().unwrap().intercepting_key_presses() { + let _ = self + .senders + .send_to_screen(ScreenInstruction::ClearKeyPressesIntercepts(client_id)); + } + } let subscriptions = subscriptions.lock().unwrap(); if subscriptions.contains(&EventType::BeforeClose) { let mut running_plugin = running_plugin.lock().unwrap(); @@ -1436,6 +1445,8 @@ impl WasmBridge { pane_id_to_replace, cwd, start_suppressed, + None, + None, Some(client_id), ))); vec![(plugin_id, Some(client_id))] diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index f8dad922..ffc3fce9 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -73,9 +73,10 @@ pub fn zellij_exports(linker: &mut Linker) { .unwrap(); } -fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) { - let env = caller.data(); - let err_context = || format!("failed to run plugin command {}", env.name()); +fn host_run_plugin_command(mut caller: Caller<'_, PluginEnv>) { + let mut env = caller.data_mut(); + let plugin_command = env.name(); + let err_context = || format!("failed to run plugin command {}", plugin_command); wasi_read_bytes(env) .and_then(|bytes| { let command: ProtobufPluginCommand = ProtobufPluginCommand::decode(bytes.as_slice())?; @@ -455,6 +456,10 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) { PluginCommand::EmbedMultiplePanes(pane_ids) => { embed_multiple_panes(env, pane_ids.into_iter().map(|p| p.into()).collect()) }, + PluginCommand::InterceptKeyPresses => intercept_key_presses(&mut env), + PluginCommand::ClearKeyPressesIntercepts => { + clear_key_presses_intercepts(&mut env) + }, }, (PermissionStatus::Denied, permission) => { log::error!( @@ -2163,6 +2168,8 @@ fn load_new_plugin( size, cwd, skip_cache, + None, + None, )); }, Err(e) => { @@ -2231,6 +2238,23 @@ fn embed_multiple_panes(env: &PluginEnv, pane_ids: Vec) { )); } +fn intercept_key_presses(env: &mut PluginEnv) { + env.intercepting_key_presses = true; + let _ = env + .senders + .send_to_screen(ScreenInstruction::InterceptKeyPresses( + env.plugin_id, + env.client_id, + )); +} + +fn clear_key_presses_intercepts(env: &mut PluginEnv) { + env.intercepting_key_presses = false; + let _ = env + .senders + .send_to_screen(ScreenInstruction::ClearKeyPressesIntercepts(env.client_id)); +} + // Custom panic handler for plugins. // // This is called when a panic occurs in a plugin. Since most panics will likely originate in the @@ -2409,6 +2433,9 @@ fn check_command_permission( PermissionType::Reconfigure }, PluginCommand::ChangeHostFolder(..) => PermissionType::FullHdAccess, + PluginCommand::InterceptKeyPresses | PluginCommand::ClearKeyPressesIntercepts => { + PermissionType::InterceptInput + }, _ => return (PermissionStatus::Granted, None), }; diff --git a/zellij-server/src/pty.rs b/zellij-server/src/pty.rs index 450f0b0b..e0abff49 100644 --- a/zellij-server/src/pty.rs +++ b/zellij-server/src/pty.rs @@ -97,6 +97,7 @@ pub enum PtyInstruction { Size, bool, // skip cache Option, // if Some, will not fill cwd but just forward the message + Option, // should focus plugin Option, ), ListClientsMetadata(SessionLayoutMetadata, ClientId), @@ -771,6 +772,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) -> Result<()> { size, skip_cache, cwd, + should_focus_plugin, floating_pane_coordinates, ) => { pty.fill_plugin_cwd( @@ -784,6 +786,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box) -> Result<()> { size, skip_cache, cwd, + should_focus_plugin, floating_pane_coordinates, )?; }, @@ -1527,9 +1530,8 @@ impl Pty { size: Size, skip_cache: bool, cwd: Option, - // left here for historical and potential future reasons since we might change the ordering - // of the pipeline between threads and end up needing to forward this - _floating_pane_coordinates: Option, + should_focus_plugin: Option, + floating_pane_coordinates: Option, ) -> Result<()> { let get_focused_cwd = || { self.active_panes @@ -1563,6 +1565,8 @@ impl Pty { size, cwd, skip_cache, + should_focus_plugin, + floating_pane_coordinates, ))?; Ok(()) } diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index be7e7d7d..64c8836e 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -9,8 +9,8 @@ use std::time::Duration; use log::{debug, warn}; use zellij_utils::data::{ - Direction, KeyWithModifier, PaneManifest, PluginPermission, Resize, ResizeStrategy, - SessionInfo, Styling, + Direction, FloatingPaneCoordinates, KeyWithModifier, PaneManifest, PluginPermission, Resize, + ResizeStrategy, SessionInfo, Styling, }; use zellij_utils::errors::prelude::*; use zellij_utils::input::command::RunCommand; @@ -32,6 +32,7 @@ use zellij_utils::{ use crate::background_jobs::BackgroundJob; use crate::os_input_output::ResizeCache; +use crate::pane_groups::PaneGroups; use crate::panes::alacritty_functions::xparse_color; use crate::panes::terminal_character::AnsiCode; use crate::session_layout_metadata::{PaneLayoutMetadata, SessionLayoutMetadata}; @@ -51,10 +52,7 @@ use crate::{ ClientId, ServerInstruction, }; use zellij_utils::{ - data::{ - Event, FloatingPaneCoordinates, InputMode, ModeInfo, Palette, PaletteColor, - PluginCapabilities, Style, TabInfo, - }, + data::{Event, InputMode, ModeInfo, Palette, PaletteColor, PluginCapabilities, Style, TabInfo}, errors::{ContextType, ScreenContext}, input::get_mode_info, ipc::{ClientAttributes, PixelDimensions, ServerToClientMsg}, @@ -305,6 +303,8 @@ pub enum ScreenInstruction { Option, Option, // cwd bool, // start suppressed + Option, + Option, // should focus plugin Option, ), UpdatePluginLoadingStage(u32, LoadingIndication), // u32 - plugin_id @@ -415,6 +415,8 @@ pub enum ScreenInstruction { EmbedMultiplePanes(Vec, ClientId), TogglePaneInGroup(ClientId), ToggleGroupMarking(ClientId), + InterceptKeyPresses(PluginId, ClientId), + ClearKeyPressesIntercepts(ClientId), } impl From<&ScreenInstruction> for ScreenContext { @@ -636,6 +638,10 @@ impl From<&ScreenInstruction> for ScreenContext { ScreenInstruction::EmbedMultiplePanes(..) => ScreenContext::EmbedMultiplePanes, ScreenInstruction::TogglePaneInGroup(..) => ScreenContext::TogglePaneInGroup, ScreenInstruction::ToggleGroupMarking(..) => ScreenContext::ToggleGroupMarking, + ScreenInstruction::InterceptKeyPresses(..) => ScreenContext::InterceptKeyPresses, + ScreenInstruction::ClearKeyPressesIntercepts(..) => { + ScreenContext::ClearKeyPressesIntercepts + }, } } } @@ -717,7 +723,7 @@ pub(crate) struct Screen { default_layout_name: Option, explicitly_disable_kitty_keyboard_protocol: bool, default_editor: Option, - current_pane_group: Rc>>>, + current_pane_group: Rc>, advanced_mouse_actions: bool, currently_marking_pane_group: Rc>>, } @@ -753,6 +759,7 @@ impl Screen { let mut session_infos_on_machine = BTreeMap::new(); let resurrectable_sessions = BTreeMap::new(); session_infos_on_machine.insert(session_name.clone(), session_info); + let current_pane_group = PaneGroups::new(bus.senders.clone()); Screen { bus, max_panes, @@ -790,7 +797,7 @@ impl Screen { layout_dir, explicitly_disable_kitty_keyboard_protocol, default_editor, - current_pane_group: Rc::new(RefCell::new(HashMap::new())), + current_pane_group: Rc::new(RefCell::new(current_pane_group)), currently_marking_pane_group: Rc::new(RefCell::new(HashMap::new())), advanced_mouse_actions, } @@ -2897,15 +2904,12 @@ impl Screen { fn get_client_pane_group(&self, client_id: &ClientId) -> HashSet { self.current_pane_group .borrow() - .get(client_id) - .map(|p| p.iter().copied().collect()) - .unwrap_or_else(|| HashSet::new()) + .get_client_pane_group(client_id) } fn clear_pane_group(&mut self, client_id: &ClientId) { self.current_pane_group .borrow_mut() - .get_mut(client_id) - .map(|p| p.clear()); + .clear_pane_group(client_id); self.currently_marking_pane_group .borrow_mut() .remove(client_id); @@ -2913,22 +2917,14 @@ impl Screen { fn toggle_pane_id_in_group(&mut self, pane_id: PaneId, client_id: &ClientId) { { let mut pane_groups = self.current_pane_group.borrow_mut(); - let client_pane_group = pane_groups.entry(*client_id).or_insert_with(|| vec![]); - if client_pane_group.contains(&pane_id) { - client_pane_group.retain(|p| p != &pane_id); - } else { - client_pane_group.push(pane_id); - }; + pane_groups.toggle_pane_id_in_group(pane_id, self.size, client_id); } self.retain_only_existing_panes_in_pane_groups(); } fn add_pane_id_to_group(&mut self, pane_id: PaneId, client_id: &ClientId) { { let mut pane_groups = self.current_pane_group.borrow_mut(); - let client_pane_group = pane_groups.entry(*client_id).or_insert_with(|| vec![]); - if !client_pane_group.contains(&pane_id) { - client_pane_group.push(pane_id); - } + pane_groups.add_pane_id_to_group(pane_id, self.size, client_id); } self.retain_only_existing_panes_in_pane_groups(); } @@ -2956,17 +2952,18 @@ impl Screen { fn group_and_ungroup_panes( &mut self, - mut pane_ids_to_group: Vec, + pane_ids_to_group: Vec, pane_ids_to_ungroup: Vec, client_id: ClientId, ) { { let mut current_pane_group = self.current_pane_group.borrow_mut(); - let client_pane_group = current_pane_group - .entry(client_id) - .or_insert_with(|| vec![]); - client_pane_group.append(&mut pane_ids_to_group); - client_pane_group.retain(|p| !pane_ids_to_ungroup.contains(p)); + current_pane_group.group_and_ungroup_panes( + pane_ids_to_group, + pane_ids_to_ungroup, + self.size, + &client_id, + ); } self.retain_only_existing_panes_in_pane_groups(); let _ = self.log_and_report_session_state(); @@ -2974,7 +2971,7 @@ impl Screen { fn retain_only_existing_panes_in_pane_groups(&mut self) { let clients_with_empty_group = { let mut clients_with_empty_group = vec![]; - let mut current_pane_group = self.current_pane_group.borrow_mut(); + let mut current_pane_group = { self.current_pane_group.borrow().clone_inner() }; for (client_id, panes_in_group) in current_pane_group.iter_mut() { let all_tabs = self.get_tabs(); panes_in_group.retain(|p_id| { @@ -2991,6 +2988,9 @@ impl Screen { clients_with_empty_group.push(*client_id) } } + self.current_pane_group + .borrow_mut() + .override_groups_with(current_pane_group); clients_with_empty_group }; for client_id in &clients_with_empty_group { @@ -3114,6 +3114,7 @@ pub(crate) fn screen_thread_main( let mut pending_events_waiting_for_tab: Vec = vec![]; let mut pending_events_waiting_for_client: Vec = vec![]; let mut plugin_loading_message_cache = HashMap::new(); + let mut keybind_intercepts = HashMap::new(); loop { let (event, mut err_ctx) = screen .bus @@ -3178,6 +3179,7 @@ pub(crate) fn screen_thread_main( invoked_with, floating_pane_coordinates, start_suppressed, + true, Some(client_id) ) }, ?); @@ -3204,6 +3206,7 @@ pub(crate) fn screen_thread_main( invoked_with, floating_pane_coordinates, start_suppressed, + true, None, )?; if let Some(hold_for_command) = hold_for_command { @@ -3226,6 +3229,7 @@ pub(crate) fn screen_thread_main( invoked_with, floating_pane_coordinates, start_suppressed, + true, None, )?; if let Some(hold_for_command) = hold_for_command { @@ -3361,6 +3365,19 @@ pub(crate) fn screen_thread_main( is_kitty_keyboard_protocol, client_id, ) => { + if let Some(plugin_id) = keybind_intercepts.get(&client_id) { + if let Some(key_with_modifier) = key_with_modifier { + let _ = screen + .bus + .senders + .send_to_plugin(PluginInstruction::Update(vec![( + Some(*plugin_id), + Some(client_id), + Event::InterceptedKeyPress(key_with_modifier), + )])); + continue; + } + } let mut state_changed = false; active_tab_and_connected_client_id!( screen, @@ -4322,6 +4339,7 @@ pub(crate) fn screen_thread_main( skip_cache, cwd, None, + None, ))?; }, ScreenInstruction::NewFloatingPluginPane( @@ -4350,6 +4368,7 @@ pub(crate) fn screen_thread_main( size, skip_cache, cwd, + None, floating_pane_coordinates, ))?; }, @@ -4385,6 +4404,7 @@ pub(crate) fn screen_thread_main( skip_cache, None, None, + None, ))?; }, None => { @@ -4419,6 +4439,8 @@ pub(crate) fn screen_thread_main( pane_id_to_replace, cwd, start_suppressed, + floating_pane_coordinates, + should_focus_plugin, client_id, ) => { if screen.active_tab_indices.is_empty() && tab_index.is_none() { @@ -4432,6 +4454,8 @@ pub(crate) fn screen_thread_main( pane_id_to_replace, cwd, start_suppressed, + floating_pane_coordinates, + should_focus_plugin, client_id, )); continue; @@ -4480,8 +4504,9 @@ pub(crate) fn screen_thread_main( Some(pane_title), should_float, Some(run_plugin), - None, + floating_pane_coordinates, start_suppressed, + should_focus_plugin.unwrap_or(true), Some(client_id), ) }, ?); @@ -4495,6 +4520,7 @@ pub(crate) fn screen_thread_main( Some(run_plugin), None, start_suppressed, + should_focus_plugin.unwrap_or(true), None, )?; } else { @@ -4571,6 +4597,7 @@ pub(crate) fn screen_thread_main( skip_cache, None, None, + None, ))?; }, None => { @@ -4618,6 +4645,7 @@ pub(crate) fn screen_thread_main( skip_cache, None, None, + None, ))?; } }, @@ -4654,6 +4682,7 @@ pub(crate) fn screen_thread_main( skip_cache, cwd, None, + None, ))?; }, None => { @@ -4691,6 +4720,7 @@ pub(crate) fn screen_thread_main( skip_cache, cwd, None, + None, ))?; }, None => { @@ -5271,6 +5301,12 @@ pub(crate) fn screen_thread_main( } let _ = screen.log_and_report_session_state(); }, + ScreenInstruction::InterceptKeyPresses(plugin_id, client_id) => { + keybind_intercepts.insert(client_id, plugin_id); + }, + ScreenInstruction::ClearKeyPressesIntercepts(client_id) => { + keybind_intercepts.remove(&client_id); + }, } } Ok(()) diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index e3a36ae5..12376817 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -22,6 +22,7 @@ use zellij_utils::position::Position; use zellij_utils::position::{Column, Line}; use crate::background_jobs::BackgroundJob; +use crate::pane_groups::PaneGroups; use crate::pty_writer::PtyWriteInstruction; use crate::screen::CopyOptions; use crate::ui::{loading_indication::LoadingIndication, pane_boundaries_frame::FrameParams}; @@ -262,7 +263,7 @@ pub(crate) struct Tab { styled_underlines: bool, explicitly_disable_kitty_keyboard_protocol: bool, mouse_hover_pane_id: HashMap, - current_pane_group: Rc>>>, + current_pane_group: Rc>, advanced_mouse_actions: bool, currently_marking_pane_group: Rc>>, } @@ -675,7 +676,7 @@ impl Tab { styled_underlines: bool, explicitly_disable_kitty_keyboard_protocol: bool, default_editor: Option, - current_pane_group: Rc>>>, + current_pane_group: Rc>, currently_marking_pane_group: Rc>>, advanced_mouse_actions: bool, ) -> Self { @@ -1187,17 +1188,17 @@ impl Tab { self.set_force_render(); } else { self.show_floating_panes(); - match self.floating_panes.last_floating_pane_id() { - Some(first_floating_pane_id) => match client_id { + match self.floating_panes.last_selectable_floating_pane_id() { + Some(last_selectable_floating_pane_id) => match client_id { Some(client_id) => { if !self.floating_panes.active_panes_contain(&client_id) { self.floating_panes - .focus_pane(first_floating_pane_id, client_id); + .focus_pane(last_selectable_floating_pane_id, client_id); } }, None => { self.floating_panes - .focus_pane_for_all_clients(first_floating_pane_id); + .focus_pane_for_all_clients(last_selectable_floating_pane_id); }, }, None => { @@ -1234,14 +1235,17 @@ impl Tab { invoked_with: Option, floating_pane_coordinates: Option, start_suppressed: bool, + should_focus_pane: bool, client_id: Option, ) -> Result<()> { let err_context = || format!("failed to create new pane with id {pid:?}"); - match should_float { - Some(true) => self.show_floating_panes(), - Some(false) => self.hide_floating_panes(), - None => {}, - }; + if should_focus_pane { + match should_float { + Some(true) => self.show_floating_panes(), + Some(false) => self.hide_floating_panes(), + None => {}, + }; + } self.close_down_to_max_terminals() .with_context(err_context)?; let mut new_pane = match pid { @@ -1316,10 +1320,26 @@ impl Tab { self.suppressed_panes .insert(pid, (is_scrollback_editor, new_pane)); Ok(()) - } else if self.floating_panes.panes_are_visible() { - self.add_floating_pane(new_pane, pid, floating_pane_coordinates, true) + } else if should_focus_pane { + if self.floating_panes.panes_are_visible() { + self.add_floating_pane(new_pane, pid, floating_pane_coordinates, true) + } else { + self.add_tiled_pane(new_pane, pid, client_id) + } } else { - self.add_tiled_pane(new_pane, pid, client_id) + match should_float { + Some(true) => { + self.add_floating_pane(new_pane, pid, floating_pane_coordinates, false) + }, + Some(false) => self.add_tiled_pane(new_pane, pid, client_id), + None => { + if self.floating_panes.panes_are_visible() { + self.add_floating_pane(new_pane, pid, floating_pane_coordinates, false) + } else { + self.add_tiled_pane(new_pane, pid, client_id) + } + }, + } } } pub fn replace_active_pane_with_editor_pane( @@ -2277,7 +2297,7 @@ impl Tab { ); let current_pane_group: HashMap> = - { self.current_pane_group.borrow().clone() }; + { self.current_pane_group.borrow().clone_inner() }; self.tiled_panes .render( output, @@ -2851,6 +2871,8 @@ impl Tab { // is opened self.tiled_panes.move_clients_out_of_pane(id); } + } else if let Some(pane) = self.floating_panes.get_pane_mut(id) { + pane.set_selectable(selectable); } // we do this here because if there is a non-selectable pane on the edge, we consider it // outside the viewport (a ui-pane, eg. the status-bar and tab-bar) and need to adjust for it @@ -2877,7 +2899,7 @@ impl Tab { if self.floating_panes.panes_contain(&id) { let _closed_pane = self.floating_panes.remove_pane(id); self.floating_panes.move_clients_out_of_pane(id); - if !self.floating_panes.has_panes() { + if !self.floating_panes.has_selectable_panes() { self.swap_layouts.reset_floating_damage(); self.hide_floating_panes(); } @@ -3663,10 +3685,9 @@ impl Tab { let err_context = || format!("failed to handle mouse event {event:?} for client {client_id}"); if !self.floating_panes.panes_are_visible() { - let search_selectable = false; if let Ok(Some(pane_id)) = self .floating_panes - .get_pinned_pane_id_at(&event.position, search_selectable) + .get_pinned_pane_id_at(&event.position, true) { // here, the floating panes are not visible, but there is a pinned pane (always // visible) that has been clicked on - so we make the entire surface visible and @@ -3674,6 +3695,15 @@ impl Tab { self.show_floating_panes(); self.floating_panes.focus_pane(pane_id, client_id); return Ok(MouseEffect::state_changed()); + } else if let Ok(Some(_pane_id)) = self + .floating_panes + .get_pinned_pane_id_at(&event.position, false) + { + // here, the floating panes are not visible, but there is a pinned pane (always + // visible) that has been clicked on - this pane however is not selectable + // (we know this because we passed "false" to get_pinned_pane_id_at) + // so we don't do anything + return Ok(MouseEffect::default()); } } let active_pane_id_before_click = self @@ -3924,8 +3954,13 @@ impl Tab { self.mouse_hover_pane_id.remove(&client_id); } else { let pane_id = pane.pid(); - if self.advanced_mouse_actions { + // if the pane is not selectable, we don't want to create a hover effect over it + // we do however want to remove the hover effect from other panes + let pane_is_selectable = pane.selectable(); + if self.advanced_mouse_actions && pane_is_selectable { self.mouse_hover_pane_id.insert(client_id, pane_id); + } else if self.advanced_mouse_actions { + self.mouse_hover_pane_id.remove(&client_id); } } }; @@ -4467,7 +4502,7 @@ impl Tab { } pub fn pane_infos(&self) -> Vec { let mut pane_info = vec![]; - let current_pane_group = { self.current_pane_group.borrow().clone() }; + let current_pane_group = { self.current_pane_group.borrow().clone_inner() }; let mut tiled_pane_info = self.tiled_panes.pane_info(¤t_pane_group); let mut floating_pane_info = self.floating_panes.pane_info(¤t_pane_group); pane_info.append(&mut tiled_pane_info); diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index acbe04c1..824325a9 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -5,6 +5,7 @@ use crate::Arc; use crate::{ os_input_output::{AsyncReader, Pid, ServerOsApi}, + pane_groups::PaneGroups, panes::PaneId, plugins::PluginInstruction, thread_bus::ThreadSenders, @@ -224,7 +225,7 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab { let copy_options = CopyOptions::default(); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); - let current_group = Rc::new(RefCell::new(HashMap::new())); + let current_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -298,7 +299,7 @@ fn create_new_tab_without_pane_frames(size: Size, default_mode: ModeInfo) -> Tab let copy_options = CopyOptions::default(); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); - let current_group = Rc::new(RefCell::new(HashMap::new())); + let current_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -387,7 +388,7 @@ fn create_new_tab_with_swap_layouts( let copy_options = CopyOptions::default(); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); - let current_group = Rc::new(RefCell::new(HashMap::new())); + let current_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -477,7 +478,7 @@ fn create_new_tab_with_os_api( let copy_options = CopyOptions::default(); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); - let current_group = Rc::new(RefCell::new(HashMap::new())); + let current_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -553,7 +554,7 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str) let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); let layout = Layout::from_str(layout, "layout_file_name".into(), None, None).unwrap(); let (tab_layout, floating_panes_layout) = layout.new_tab(); - let current_group = Rc::new(RefCell::new(HashMap::new())); + let current_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -643,7 +644,7 @@ fn create_new_tab_with_mock_pty_writer( let copy_options = CopyOptions::default(); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); - let current_group = Rc::new(RefCell::new(HashMap::new())); + let current_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -724,7 +725,7 @@ fn create_new_tab_with_sixel_support( let terminal_emulator_colors = Rc::new(RefCell::new(Palette::default())); let copy_options = CopyOptions::default(); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); - let current_group = Rc::new(RefCell::new(HashMap::new())); + let current_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -912,6 +913,7 @@ fn increase_tiled_pane_sizes_with_stacked_resizes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -965,6 +967,7 @@ fn increase_tiled_pane_sizes_with_stacked_resizes_into_uneven_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1027,6 +1030,7 @@ fn split_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1067,6 +1071,7 @@ fn split_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1109,6 +1114,7 @@ fn render_stacks_without_pane_frames() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1129,6 +1135,7 @@ fn render_stacks_without_pane_frames() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1143,6 +1150,7 @@ fn render_stacks_without_pane_frames() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1157,6 +1165,7 @@ fn render_stacks_without_pane_frames() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1193,8 +1202,17 @@ fn dump_screen() { ..Default::default() }); let new_pane_id = PaneId::Terminal(2); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes(2, Vec::from("scratch".as_bytes())) .unwrap(); let file = "/tmp/log.sh"; @@ -1221,8 +1239,17 @@ fn clear_screen() { ..Default::default() }); let new_pane_id = PaneId::Terminal(2); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes(2, Vec::from("scratch".as_bytes())) .unwrap(); let file = "/tmp/log-clear-screen.sh"; @@ -1247,8 +1274,17 @@ fn new_floating_pane() { let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am scratch terminal".as_bytes()), @@ -1275,8 +1311,17 @@ fn floating_panes_persist_across_toggles() { let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); // here we send bytes to the pane when it's not visible to make sure they're still handled and // we see them once we toggle the panes back @@ -1307,8 +1352,17 @@ fn toggle_floating_panes_off() { let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am scratch terminal".as_bytes()), @@ -1336,8 +1390,17 @@ fn toggle_floating_panes_on() { let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am scratch terminal".as_bytes()), @@ -1377,6 +1440,7 @@ fn five_new_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1387,6 +1451,7 @@ fn five_new_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1397,6 +1462,7 @@ fn five_new_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1407,6 +1473,7 @@ fn five_new_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1417,6 +1484,7 @@ fn five_new_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1461,6 +1529,7 @@ fn increase_floating_pane_size() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1499,6 +1568,7 @@ fn decrease_floating_pane_size() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1537,6 +1607,7 @@ fn resize_floating_pane_left() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1578,6 +1649,7 @@ fn resize_floating_pane_right() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1619,6 +1691,7 @@ fn resize_floating_pane_up() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1660,6 +1733,7 @@ fn resize_floating_pane_down() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1705,6 +1779,7 @@ fn move_floating_pane_focus_left() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1715,6 +1790,7 @@ fn move_floating_pane_focus_left() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1725,6 +1801,7 @@ fn move_floating_pane_focus_left() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1735,6 +1812,7 @@ fn move_floating_pane_focus_left() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1745,6 +1823,7 @@ fn move_floating_pane_focus_left() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1800,6 +1879,7 @@ fn move_floating_pane_focus_right() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1810,6 +1890,7 @@ fn move_floating_pane_focus_right() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1820,6 +1901,7 @@ fn move_floating_pane_focus_right() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1830,6 +1912,7 @@ fn move_floating_pane_focus_right() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1840,6 +1923,7 @@ fn move_floating_pane_focus_right() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1896,6 +1980,7 @@ fn move_floating_pane_focus_up() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1906,6 +1991,7 @@ fn move_floating_pane_focus_up() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1916,6 +2002,7 @@ fn move_floating_pane_focus_up() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1926,6 +2013,7 @@ fn move_floating_pane_focus_up() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1936,6 +2024,7 @@ fn move_floating_pane_focus_up() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1991,6 +2080,7 @@ fn move_floating_pane_focus_down() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2001,6 +2091,7 @@ fn move_floating_pane_focus_down() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2011,6 +2102,7 @@ fn move_floating_pane_focus_down() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2021,6 +2113,7 @@ fn move_floating_pane_focus_down() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2031,6 +2124,7 @@ fn move_floating_pane_focus_down() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2087,6 +2181,7 @@ fn move_floating_pane_focus_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2097,6 +2192,7 @@ fn move_floating_pane_focus_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2107,6 +2203,7 @@ fn move_floating_pane_focus_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2117,6 +2214,7 @@ fn move_floating_pane_focus_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2127,6 +2225,7 @@ fn move_floating_pane_focus_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2191,6 +2290,7 @@ fn move_pane_focus_with_mouse_to_non_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2201,6 +2301,7 @@ fn move_pane_focus_with_mouse_to_non_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2211,6 +2312,7 @@ fn move_pane_focus_with_mouse_to_non_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2221,6 +2323,7 @@ fn move_pane_focus_with_mouse_to_non_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2231,6 +2334,7 @@ fn move_pane_focus_with_mouse_to_non_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2295,6 +2399,7 @@ fn drag_pane_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2305,6 +2410,7 @@ fn drag_pane_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2315,6 +2421,7 @@ fn drag_pane_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2325,6 +2432,7 @@ fn drag_pane_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2335,6 +2443,7 @@ fn drag_pane_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2399,6 +2508,7 @@ fn mark_text_inside_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2409,6 +2519,7 @@ fn mark_text_inside_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2419,6 +2530,7 @@ fn mark_text_inside_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2429,6 +2541,7 @@ fn mark_text_inside_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2439,6 +2552,7 @@ fn mark_text_inside_floating_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2511,6 +2625,7 @@ fn resize_tab_with_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2521,6 +2636,7 @@ fn resize_tab_with_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2531,6 +2647,7 @@ fn resize_tab_with_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2541,6 +2658,7 @@ fn resize_tab_with_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2551,6 +2669,7 @@ fn resize_tab_with_floating_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2605,6 +2724,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2615,6 +2735,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2625,6 +2746,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2635,6 +2757,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2645,6 +2768,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2695,6 +2819,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_b None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2705,6 +2830,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_b None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2715,6 +2841,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_b None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2725,6 +2852,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_b None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2735,6 +2863,7 @@ fn shrink_whole_tab_with_floating_panes_horizontally_and_vertically_and_expand_b None, None, false, + true, Some(client_id), ) .unwrap(); @@ -2779,8 +2908,17 @@ fn embed_floating_pane() { let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am scratch terminal".as_bytes()), @@ -2807,8 +2945,17 @@ fn float_embedded_pane() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am an embedded pane".as_bytes()), @@ -2837,8 +2984,17 @@ fn embed_floating_pane_without_pane_frames() { let mut output = Output::default(); tab.set_pane_frames(false); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am scratch terminal".as_bytes()), @@ -2866,8 +3022,17 @@ fn float_embedded_pane_without_pane_frames() { let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); tab.set_pane_frames(false); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am an embedded pane".as_bytes()), @@ -2969,8 +3134,17 @@ fn rename_floating_pane() { let mut tab = create_new_tab(size, ModeInfo::default()); let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.handle_pty_bytes( 2, Vec::from("\n\n\n I am a floating pane".as_bytes()), @@ -3065,8 +3239,17 @@ fn move_floating_pane_with_sixel_image() { let mut output = Output::new(sixel_image_store.clone(), character_cell_size, true); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); let fixture = read_fixture("sixel-image-500px.six"); tab.handle_pty_bytes(2, fixture).unwrap(); tab.handle_mouse_event( @@ -3109,8 +3292,17 @@ fn floating_pane_above_sixel_image() { let mut output = Output::new(sixel_image_store.clone(), character_cell_size, true); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); let fixture = read_fixture("sixel-image-500px.six"); tab.handle_pty_bytes(1, fixture).unwrap(); tab.handle_mouse_event( @@ -3173,8 +3365,17 @@ fn suppress_floating_pane() { let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) @@ -3229,8 +3430,17 @@ fn close_suppressing_floating_pane() { let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) @@ -3289,8 +3499,17 @@ fn suppress_floating_pane_embed_it_and_close_it() { let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) @@ -3351,8 +3570,17 @@ fn resize_whole_tab_while_floting_pane_is_suppressed() { let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); tab.replace_active_pane_with_editor_pane(editor_pane_id, client_id) .unwrap(); tab.handle_pty_bytes(3, Vec::from("\n\n\nI am an editor pane".as_bytes())) @@ -3453,8 +3681,17 @@ fn enter_search_floating_pane() { let new_pane_id = PaneId::Terminal(2); let mut output = Output::default(); tab.toggle_floating_panes(Some(client_id), None).unwrap(); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(client_id)) - .unwrap(); + tab.new_pane( + new_pane_id, + None, + None, + None, + None, + false, + true, + Some(client_id), + ) + .unwrap(); let pane_content = read_fixture("grid_copy"); tab.handle_pty_bytes(2, pane_content).unwrap(); @@ -4227,6 +4464,7 @@ fn move_pane_focus_sends_tty_csi_event() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4270,6 +4508,7 @@ fn move_floating_pane_focus_sends_tty_csi_event() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4280,6 +4519,7 @@ fn move_floating_pane_focus_sends_tty_csi_event() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4329,6 +4569,7 @@ fn toggle_floating_panes_on_sends_tty_csi_event() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4339,6 +4580,7 @@ fn toggle_floating_panes_on_sends_tty_csi_event() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4389,6 +4631,7 @@ fn toggle_floating_panes_off_sends_tty_csi_event() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4399,6 +4642,7 @@ fn toggle_floating_panes_off_sends_tty_csi_event() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4469,6 +4713,7 @@ fn can_swap_tiled_layout_at_runtime() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4534,6 +4779,7 @@ fn can_swap_floating_layout_at_runtime() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4544,6 +4790,7 @@ fn can_swap_floating_layout_at_runtime() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4605,6 +4852,7 @@ fn swapping_layouts_after_resize_snaps_to_current_layout() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4665,6 +4913,7 @@ fn swap_tiled_layout_with_stacked_children() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4675,6 +4924,7 @@ fn swap_tiled_layout_with_stacked_children() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4685,6 +4935,7 @@ fn swap_tiled_layout_with_stacked_children() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4738,6 +4989,7 @@ fn swap_tiled_layout_with_only_stacked_children() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4748,6 +5000,7 @@ fn swap_tiled_layout_with_only_stacked_children() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4758,6 +5011,7 @@ fn swap_tiled_layout_with_only_stacked_children() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4814,6 +5068,7 @@ fn swap_tiled_layout_with_stacked_children_and_no_pane_frames() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4824,6 +5079,7 @@ fn swap_tiled_layout_with_stacked_children_and_no_pane_frames() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4834,6 +5090,7 @@ fn swap_tiled_layout_with_stacked_children_and_no_pane_frames() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4890,6 +5147,7 @@ fn move_focus_up_with_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4900,6 +5158,7 @@ fn move_focus_up_with_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4910,6 +5169,7 @@ fn move_focus_up_with_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4968,6 +5228,7 @@ fn move_focus_down_with_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4978,6 +5239,7 @@ fn move_focus_down_with_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -4988,6 +5250,7 @@ fn move_focus_down_with_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5048,6 +5311,7 @@ fn move_focus_right_into_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5119,6 +5383,7 @@ fn move_focus_left_into_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5192,6 +5457,7 @@ fn move_focus_up_into_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5266,6 +5532,7 @@ fn move_focus_down_into_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5336,6 +5603,7 @@ fn close_main_stacked_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5346,6 +5614,7 @@ fn close_main_stacked_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5356,6 +5625,7 @@ fn close_main_stacked_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5415,6 +5685,7 @@ fn close_main_stacked_pane_in_mid_stack() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5425,6 +5696,7 @@ fn close_main_stacked_pane_in_mid_stack() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5435,6 +5707,7 @@ fn close_main_stacked_pane_in_mid_stack() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5445,6 +5718,7 @@ fn close_main_stacked_pane_in_mid_stack() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5455,6 +5729,7 @@ fn close_main_stacked_pane_in_mid_stack() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5517,6 +5792,7 @@ fn close_one_liner_stacked_pane_below_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5527,6 +5803,7 @@ fn close_one_liner_stacked_pane_below_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5537,6 +5814,7 @@ fn close_one_liner_stacked_pane_below_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5547,6 +5825,7 @@ fn close_one_liner_stacked_pane_below_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5557,6 +5836,7 @@ fn close_one_liner_stacked_pane_below_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5620,6 +5900,7 @@ fn close_one_liner_stacked_pane_above_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5630,6 +5911,7 @@ fn close_one_liner_stacked_pane_above_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5640,6 +5922,7 @@ fn close_one_liner_stacked_pane_above_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5650,6 +5933,7 @@ fn close_one_liner_stacked_pane_above_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5660,6 +5944,7 @@ fn close_one_liner_stacked_pane_above_main_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5722,6 +6007,7 @@ fn can_increase_size_of_main_pane_in_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5732,6 +6018,7 @@ fn can_increase_size_of_main_pane_in_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5742,6 +6029,7 @@ fn can_increase_size_of_main_pane_in_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5752,6 +6040,7 @@ fn can_increase_size_of_main_pane_in_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5762,6 +6051,7 @@ fn can_increase_size_of_main_pane_in_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5828,6 +6118,7 @@ fn can_increase_size_of_main_pane_in_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5838,6 +6129,7 @@ fn can_increase_size_of_main_pane_in_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5848,6 +6140,7 @@ fn can_increase_size_of_main_pane_in_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5858,6 +6151,7 @@ fn can_increase_size_of_main_pane_in_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5868,6 +6162,7 @@ fn can_increase_size_of_main_pane_in_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5934,6 +6229,7 @@ fn can_increase_size_of_main_pane_in_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5944,6 +6240,7 @@ fn can_increase_size_of_main_pane_in_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5954,6 +6251,7 @@ fn can_increase_size_of_main_pane_in_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5964,6 +6262,7 @@ fn can_increase_size_of_main_pane_in_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -5974,6 +6273,7 @@ fn can_increase_size_of_main_pane_in_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6035,6 +6335,7 @@ fn can_increase_size_into_pane_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6045,6 +6346,7 @@ fn can_increase_size_into_pane_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6055,6 +6357,7 @@ fn can_increase_size_into_pane_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6065,6 +6368,7 @@ fn can_increase_size_into_pane_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6075,6 +6379,7 @@ fn can_increase_size_into_pane_stack_horizontally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6140,6 +6445,7 @@ fn can_increase_size_into_pane_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6150,6 +6456,7 @@ fn can_increase_size_into_pane_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6160,6 +6467,7 @@ fn can_increase_size_into_pane_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6170,6 +6478,7 @@ fn can_increase_size_into_pane_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6180,6 +6489,7 @@ fn can_increase_size_into_pane_stack_vertically() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6248,6 +6558,7 @@ fn can_increase_size_into_pane_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6258,6 +6569,7 @@ fn can_increase_size_into_pane_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6268,6 +6580,7 @@ fn can_increase_size_into_pane_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6278,6 +6591,7 @@ fn can_increase_size_into_pane_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6288,6 +6602,7 @@ fn can_increase_size_into_pane_stack_non_directionally() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6348,6 +6663,7 @@ fn decreasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6358,6 +6674,7 @@ fn decreasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6368,6 +6685,7 @@ fn decreasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6378,6 +6696,7 @@ fn decreasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6388,6 +6707,7 @@ fn decreasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6450,6 +6770,7 @@ fn increasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6460,6 +6781,7 @@ fn increasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6470,6 +6792,7 @@ fn increasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6480,6 +6803,7 @@ fn increasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6490,6 +6814,7 @@ fn increasing_size_of_whole_tab_treats_stacked_panes_properly() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6557,6 +6882,7 @@ fn cannot_decrease_stack_size_beyond_minimum_height() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6567,6 +6893,7 @@ fn cannot_decrease_stack_size_beyond_minimum_height() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6577,6 +6904,7 @@ fn cannot_decrease_stack_size_beyond_minimum_height() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6587,6 +6915,7 @@ fn cannot_decrease_stack_size_beyond_minimum_height() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6597,6 +6926,7 @@ fn cannot_decrease_stack_size_beyond_minimum_height() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6664,6 +6994,7 @@ fn focus_stacked_pane_over_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6674,6 +7005,7 @@ fn focus_stacked_pane_over_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6684,6 +7016,7 @@ fn focus_stacked_pane_over_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6694,6 +7027,7 @@ fn focus_stacked_pane_over_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6704,6 +7038,7 @@ fn focus_stacked_pane_over_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6768,6 +7103,7 @@ fn focus_stacked_pane_under_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6778,6 +7114,7 @@ fn focus_stacked_pane_under_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6788,6 +7125,7 @@ fn focus_stacked_pane_under_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6798,6 +7136,7 @@ fn focus_stacked_pane_under_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6808,6 +7147,7 @@ fn focus_stacked_pane_under_flexible_pane_with_the_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6877,6 +7217,7 @@ fn close_stacked_pane_with_previously_focused_other_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6887,6 +7228,7 @@ fn close_stacked_pane_with_previously_focused_other_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6897,6 +7239,7 @@ fn close_stacked_pane_with_previously_focused_other_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6907,6 +7250,7 @@ fn close_stacked_pane_with_previously_focused_other_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6917,6 +7261,7 @@ fn close_stacked_pane_with_previously_focused_other_pane() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -6992,6 +7337,7 @@ fn close_pane_near_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7002,6 +7348,7 @@ fn close_pane_near_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7012,6 +7359,7 @@ fn close_pane_near_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7022,6 +7370,7 @@ fn close_pane_near_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7032,6 +7381,7 @@ fn close_pane_near_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7098,6 +7448,7 @@ fn focus_next_pane_expands_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7108,6 +7459,7 @@ fn focus_next_pane_expands_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7118,6 +7470,7 @@ fn focus_next_pane_expands_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7128,6 +7481,7 @@ fn focus_next_pane_expands_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7138,6 +7492,7 @@ fn focus_next_pane_expands_stacked_panes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7200,6 +7555,7 @@ fn stacked_panes_can_become_fullscreen() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7210,6 +7566,7 @@ fn stacked_panes_can_become_fullscreen() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7220,6 +7577,7 @@ fn stacked_panes_can_become_fullscreen() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7230,6 +7588,7 @@ fn stacked_panes_can_become_fullscreen() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7240,6 +7599,7 @@ fn stacked_panes_can_become_fullscreen() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7898,6 +8258,7 @@ fn new_pane_in_auto_layout() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -7968,6 +8329,7 @@ fn new_pane_in_stacked_resizes() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -8919,6 +9281,7 @@ fn new_floating_pane_in_auto_layout() { None, None, false, + true, Some(client_id), ) .unwrap(); diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index f80b870b..67115118 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -1,4 +1,5 @@ use super::Tab; +use crate::pane_groups::PaneGroups; use crate::panes::sixel::SixelImageStore; use crate::screen::CopyOptions; use crate::{ @@ -165,7 +166,7 @@ fn create_new_tab(size: Size, stacked_resize: bool) -> Tab { let copy_options = CopyOptions::default(); let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); - let current_pane_group = Rc::new(RefCell::new(HashMap::new())); + let current_pane_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -238,7 +239,7 @@ fn create_new_tab_with_layout(size: Size, layout: TiledPaneLayout) -> Tab { let copy_options = CopyOptions::default(); let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); - let current_pane_group = Rc::new(RefCell::new(HashMap::new())); + let current_pane_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -317,7 +318,7 @@ fn create_new_tab_with_cell_size( let sixel_image_store = Rc::new(RefCell::new(SixelImageStore::default())); let terminal_emulator_color_codes = Rc::new(RefCell::new(HashMap::new())); let stacked_resize = Rc::new(RefCell::new(true)); - let current_pane_group = Rc::new(RefCell::new(HashMap::new())); + let current_pane_group = Rc::new(RefCell::new(PaneGroups::new(ThreadSenders::default()))); let currently_marking_pane_group = Rc::new(RefCell::new(HashMap::new())); let debug = false; let arrow_fonts = true; @@ -602,7 +603,7 @@ fn split_largest_pane() { let mut tab = create_new_tab(size, stacked_resize); for i in 2..5 { let new_pane_id = PaneId::Terminal(i); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(1)) + tab.new_pane(new_pane_id, None, None, None, None, false, true, Some(1)) .unwrap(); } assert_eq!(tab.tiled_panes.panes.len(), 4, "The tab has four panes"); @@ -811,8 +812,17 @@ pub fn cannot_split_largest_pane_when_there_is_no_room() { let size = Size { cols: 8, rows: 4 }; let stacked_resize = true; let mut tab = create_new_tab(size, stacked_resize); - tab.new_pane(PaneId::Terminal(2), None, None, None, None, false, Some(1)) - .unwrap(); + tab.new_pane( + PaneId::Terminal(2), + None, + None, + None, + None, + false, + true, + Some(1), + ) + .unwrap(); assert_eq!( tab.tiled_panes.panes.len(), 1, @@ -856,7 +866,7 @@ pub fn toggle_focused_pane_fullscreen() { let mut tab = create_new_tab(size, stacked_resize); for i in 2..5 { let new_pane_id = PaneId::Terminal(i); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(1)) + tab.new_pane(new_pane_id, None, None, None, None, false, true, Some(1)) .unwrap(); } tab.toggle_active_pane_fullscreen(1); @@ -932,7 +942,7 @@ pub fn toggle_focused_pane_fullscreen_with_stacked_resizes() { let mut tab = create_new_tab(size, stacked_resize); for i in 2..5 { let new_pane_id = PaneId::Terminal(i); - tab.new_pane(new_pane_id, None, None, None, None, false, Some(1)) + tab.new_pane(new_pane_id, None, None, None, None, false, true, Some(1)) .unwrap(); } tab.toggle_active_pane_fullscreen(1); @@ -1008,16 +1018,52 @@ fn switch_to_next_pane_fullscreen() { let mut active_tab = create_new_tab(size, stacked_resize); active_tab - .new_pane(PaneId::Terminal(1), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(1), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab - .new_pane(PaneId::Terminal(2), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(2), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab - .new_pane(PaneId::Terminal(3), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(3), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab - .new_pane(PaneId::Terminal(4), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(4), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab.toggle_active_pane_fullscreen(1); @@ -1049,16 +1095,52 @@ fn switch_to_prev_pane_fullscreen() { //testing four consecutive switches in fullscreen mode active_tab - .new_pane(PaneId::Terminal(1), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(1), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab - .new_pane(PaneId::Terminal(2), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(2), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab - .new_pane(PaneId::Terminal(3), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(3), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab - .new_pane(PaneId::Terminal(4), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(4), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab.toggle_active_pane_fullscreen(1); // order is now 1 2 3 4 @@ -14650,8 +14732,17 @@ fn correctly_resize_frameless_panes_on_pane_close() { let content_size = (pane.get_content_columns(), pane.get_content_rows()); assert_eq!(content_size, (cols, rows)); - tab.new_pane(PaneId::Terminal(2), None, None, None, None, false, Some(1)) - .unwrap(); + tab.new_pane( + PaneId::Terminal(2), + None, + None, + None, + None, + false, + true, + Some(1), + ) + .unwrap(); tab.close_pane(PaneId::Terminal(2), true); // the size should be the same after adding and then removing a pane diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs index 35979bd4..2b0d02eb 100644 --- a/zellij-server/src/ui/pane_boundaries_frame.rs +++ b/zellij-server/src/ui/pane_boundaries_frame.rs @@ -64,6 +64,7 @@ pub struct FrameParams { pub pane_is_floating: bool, pub content_offset: Offset, pub mouse_is_hovering_over_pane: bool, + pub pane_is_selectable: bool, } #[derive(Default, PartialEq)] @@ -86,6 +87,7 @@ pub struct PaneFrame { is_floating: bool, content_offset: Offset, mouse_is_hovering_over_pane: bool, + is_selectable: bool, } impl PaneFrame { @@ -114,6 +116,7 @@ impl PaneFrame { is_floating: frame_params.pane_is_floating, content_offset: frame_params.content_offset, mouse_is_hovering_over_pane: frame_params.mouse_is_hovering_over_pane, + is_selectable: frame_params.pane_is_selectable, } } pub fn is_pinned(mut self, is_pinned: bool) -> Self { @@ -167,7 +170,7 @@ impl PaneFrame { // string and length because of color let has_scroll = self.scroll_position.0 > 0 || self.scroll_position.1 > 0; if has_scroll { - let pin_indication = if self.is_floating { + let pin_indication = if self.is_floating && self.is_selectable { self.render_pinned_indication(max_length) } else { None @@ -192,7 +195,7 @@ impl PaneFrame { (None, Some(scroll_indication)) => Some(scroll_indication), _ => None, } - } else if self.is_floating { + } else if self.is_floating && self.is_selectable { self.render_pinned_indication(max_length) } else { None diff --git a/zellij-server/src/ui/pane_contents_and_ui.rs b/zellij-server/src/ui/pane_contents_and_ui.rs index d3d99f0e..c17a9b66 100644 --- a/zellij-server/src/ui/pane_contents_and_ui.rs +++ b/zellij-server/src/ui/pane_contents_and_ui.rs @@ -207,6 +207,7 @@ impl<'a> PaneContentsAndUi<'a> { client_mode: InputMode, session_is_mirrored: bool, pane_is_floating: bool, + pane_is_selectable: bool, ) -> Result<()> { let err_context = || format!("failed to render pane frame for client {client_id}"); @@ -243,6 +244,7 @@ impl<'a> PaneContentsAndUi<'a> { mouse_is_hovering_over_pane: self .mouse_is_hovering_over_pane_for_clients .contains(&client_id), + pane_is_selectable, } } else { FrameParams { @@ -260,6 +262,7 @@ impl<'a> PaneContentsAndUi<'a> { mouse_is_hovering_over_pane: self .mouse_is_hovering_over_pane_for_clients .contains(&client_id), + pane_is_selectable, } }; diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 9e744097..e2b28ed3 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -1194,7 +1194,16 @@ fn switch_to_tab_with_fullscreen() { { let active_tab = screen.get_active_tab_mut(1).unwrap(); active_tab - .new_pane(PaneId::Terminal(2), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(2), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab.toggle_active_pane_fullscreen(1); } @@ -1309,7 +1318,16 @@ fn attach_after_first_tab_closed() { { let active_tab = screen.get_active_tab_mut(1).unwrap(); active_tab - .new_pane(PaneId::Terminal(2), None, None, None, None, false, Some(1)) + .new_pane( + PaneId::Terminal(2), + None, + None, + None, + None, + false, + true, + Some(1), + ) .unwrap(); active_tab.toggle_active_pane_fullscreen(1); } @@ -1345,6 +1363,7 @@ fn open_new_floating_pane_with_custom_coordinates() { pinned: None, }), false, + true, Some(1), ) .unwrap(); @@ -1380,6 +1399,7 @@ fn open_new_floating_pane_with_custom_coordinates_exceeding_viewport() { pinned: None, }), false, + true, Some(1), ) .unwrap(); @@ -1478,7 +1498,11 @@ fn group_panes_with_mouse() { ); assert_eq!( - screen.current_pane_group.borrow().get(&client_id), + screen + .current_pane_group + .borrow() + .clone_inner() + .get(&client_id), Some(&vec![PaneId::Terminal(2)]), "Pane Id added to client's pane group" ); @@ -1489,7 +1513,11 @@ fn group_panes_with_mouse() { ); assert_eq!( - screen.current_pane_group.borrow().get(&client_id), + screen + .current_pane_group + .borrow() + .clone_inner() + .get(&client_id), Some(&vec![]), "Pane Id removed from client's pane group" ); @@ -1509,7 +1537,11 @@ fn group_panes_with_keyboard() { let _ = screen.toggle_pane_in_group(client_id); assert_eq!( - screen.current_pane_group.borrow().get(&client_id), + screen + .current_pane_group + .borrow() + .clone_inner() + .get(&client_id), Some(&vec![PaneId::Terminal(2)]), "Pane Id added to client's pane group" ); @@ -1517,7 +1549,11 @@ fn group_panes_with_keyboard() { let _ = screen.toggle_pane_in_group(client_id); assert_eq!( - screen.current_pane_group.borrow().get(&client_id), + screen + .current_pane_group + .borrow() + .clone_inner() + .get(&client_id), Some(&vec![]), "Pane Id removed from client's pane group" ); @@ -1546,6 +1582,7 @@ fn group_panes_following_focus() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1560,7 +1597,11 @@ fn group_panes_following_focus() { .unwrap(); screen.add_active_pane_to_group_if_marking(&client_id); assert_eq!( - screen.current_pane_group.borrow().get(&client_id), + screen + .current_pane_group + .borrow() + .clone_inner() + .get(&client_id), Some(&vec![PaneId::Terminal(4), PaneId::Terminal(3)]), "Pane Id of focused pane and newly focused pane above added to pane group" ); @@ -1573,7 +1614,7 @@ fn group_panes_following_focus() { .move_focus_up(client_id) .unwrap(); let _ = screen.add_active_pane_to_group_if_marking(&client_id); - assert_eq!(screen.current_pane_group.borrow().get(&client_id), Some(&vec![PaneId::Terminal(4), PaneId::Terminal(3)]), "Pane Id of newly focused pane not added to group after the group marking was toggled off"); + assert_eq!(screen.current_pane_group.borrow().clone_inner().get(&client_id), Some(&vec![PaneId::Terminal(4), PaneId::Terminal(3)]), "Pane Id of newly focused pane not added to group after the group marking was toggled off"); } } @@ -1600,6 +1641,7 @@ fn break_group_with_mouse() { None, None, false, + true, Some(client_id), ) .unwrap(); @@ -1620,7 +1662,11 @@ fn break_group_with_mouse() { .unwrap(); screen.add_active_pane_to_group_if_marking(&client_id); assert_eq!( - screen.current_pane_group.borrow().get(&client_id), + screen + .current_pane_group + .borrow() + .clone_inner() + .get(&client_id), Some(&vec![ PaneId::Terminal(4), PaneId::Terminal(3), @@ -1635,7 +1681,11 @@ fn break_group_with_mouse() { client_id, ); assert_eq!( - screen.current_pane_group.borrow().get(&client_id), + screen + .current_pane_group + .borrow() + .clone_inner() + .get(&client_id), Some(&vec![]), "Group cleared by mouse event" ); diff --git a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap index cd58c620..e4b7c405 100644 --- a/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap +++ b/zellij-server/src/unit/snapshots/zellij_server__screen__screen_tests__send_cli_launch_or_focus_plugin_action.snap @@ -1,6 +1,5 @@ --- source: zellij-server/src/./unit/screen_tests.rs -assertion_line: 2983 expression: "format!(\"{:#?}\", pty_fill_plugin_cwd_instruction)" --- Some( @@ -32,5 +31,6 @@ Some( false, None, None, + None, ), ) diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs index db6ea180..d67768f1 100644 --- a/zellij-tile/src/shim.rs +++ b/zellij-tile/src/shim.rs @@ -1313,6 +1313,20 @@ pub fn embed_multiple_panes(pane_ids: Vec) { unsafe { host_run_plugin_command() }; } +pub fn intercept_key_presses() { + let plugin_command = PluginCommand::InterceptKeyPresses; + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + +pub fn clear_key_presses_intercepts() { + let plugin_command = PluginCommand::ClearKeyPressesIntercepts; + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + // Utility Functions #[allow(unused)] diff --git a/zellij-tile/src/ui_components/text.rs b/zellij-tile/src/ui_components/text.rs index 228b8975..787125b5 100644 --- a/zellij-tile/src/ui_components/text.rs +++ b/zellij-tile/src/ui_components/text.rs @@ -54,6 +54,44 @@ impl Text { .map(|i| i.append(&mut indices.into_iter().collect())); self } + pub fn color_substring>(mut self, index_level: usize, substr: S) -> Self { + let substr = substr.as_ref(); + let mut start = 0; + + while let Some(pos) = self.text[start..].find(substr) { + let abs_pos = start + pos; + self = self.color_range(index_level, abs_pos..abs_pos + substr.len()); + start = abs_pos + substr.len(); + } + + self + } + + pub fn color_all(self, index_level: usize) -> Self { + self.color_range(index_level, ..) + } + + pub fn color_nth_substring>( + self, + index_level: usize, + substr: S, + occurrence_index: usize, + ) -> Self { + let substr = substr.as_ref(); + let mut start = 0; + let mut count = 0; + + while let Some(pos) = self.text[start..].find(substr) { + if count == occurrence_index { + let abs_pos = start + pos; + return self.color_range(index_level, abs_pos..abs_pos + substr.len()); + } + count += 1; + start = start + pos + substr.len(); + } + + self + } fn pad_indices(&mut self, index_level: usize) { if self.indices.get(index_level).is_none() { for _ in self.indices.len()..=index_level { diff --git a/zellij-utils/assets/config/default.kdl b/zellij-utils/assets/config/default.kdl index bdfedc86..722d9eff 100644 --- a/zellij-utils/assets/config/default.kdl +++ b/zellij-utils/assets/config/default.kdl @@ -181,12 +181,6 @@ keybinds { bind "Alt -" { Resize "Decrease"; } bind "Alt [" { PreviousSwapLayout; } bind "Alt ]" { NextSwapLayout; } - bind "Alt m" { - LaunchOrFocusPlugin "zellij:multiple-select" { - floating true - move_to_focused_tab true - } - } bind "Alt p" { TogglePaneInGroup; } bind "Alt Shift p" { ToggleGroupMarking; } } diff --git a/zellij-utils/assets/plugins/about.wasm b/zellij-utils/assets/plugins/about.wasm index c7355f84..07ac7021 100755 Binary files a/zellij-utils/assets/plugins/about.wasm and b/zellij-utils/assets/plugins/about.wasm differ diff --git a/zellij-utils/assets/plugins/compact-bar.wasm b/zellij-utils/assets/plugins/compact-bar.wasm index fab6fbac..3918af37 100755 Binary files a/zellij-utils/assets/plugins/compact-bar.wasm and b/zellij-utils/assets/plugins/compact-bar.wasm differ diff --git a/zellij-utils/assets/plugins/configuration.wasm b/zellij-utils/assets/plugins/configuration.wasm index 0fd47e93..a2aa03fe 100755 Binary files a/zellij-utils/assets/plugins/configuration.wasm and b/zellij-utils/assets/plugins/configuration.wasm differ diff --git a/zellij-utils/assets/plugins/fixture-plugin-for-tests.wasm b/zellij-utils/assets/plugins/fixture-plugin-for-tests.wasm index e3135dea..be0bd88a 100755 Binary files a/zellij-utils/assets/plugins/fixture-plugin-for-tests.wasm and b/zellij-utils/assets/plugins/fixture-plugin-for-tests.wasm differ diff --git a/zellij-utils/assets/plugins/multiple-select.wasm b/zellij-utils/assets/plugins/multiple-select.wasm index c3b73e96..584569c2 100755 Binary files a/zellij-utils/assets/plugins/multiple-select.wasm and b/zellij-utils/assets/plugins/multiple-select.wasm differ diff --git a/zellij-utils/assets/plugins/plugin-manager.wasm b/zellij-utils/assets/plugins/plugin-manager.wasm index 87617d79..3817aa9e 100755 Binary files a/zellij-utils/assets/plugins/plugin-manager.wasm and b/zellij-utils/assets/plugins/plugin-manager.wasm differ diff --git a/zellij-utils/assets/plugins/session-manager.wasm b/zellij-utils/assets/plugins/session-manager.wasm index fb2ac62b..17cd792c 100755 Binary files a/zellij-utils/assets/plugins/session-manager.wasm and b/zellij-utils/assets/plugins/session-manager.wasm differ diff --git a/zellij-utils/assets/plugins/status-bar.wasm b/zellij-utils/assets/plugins/status-bar.wasm index 4465559e..fefe06ba 100755 Binary files a/zellij-utils/assets/plugins/status-bar.wasm and b/zellij-utils/assets/plugins/status-bar.wasm differ diff --git a/zellij-utils/assets/plugins/strider.wasm b/zellij-utils/assets/plugins/strider.wasm index 5e57d392..ae11f8e0 100755 Binary files a/zellij-utils/assets/plugins/strider.wasm and b/zellij-utils/assets/plugins/strider.wasm differ diff --git a/zellij-utils/assets/plugins/tab-bar.wasm b/zellij-utils/assets/plugins/tab-bar.wasm index 07ba9f24..5f1e2c9f 100755 Binary files a/zellij-utils/assets/plugins/tab-bar.wasm and b/zellij-utils/assets/plugins/tab-bar.wasm differ diff --git a/zellij-utils/assets/prost/api.event.rs b/zellij-utils/assets/prost/api.event.rs index 258dba41..7ec6e076 100644 --- a/zellij-utils/assets/prost/api.event.rs +++ b/zellij-utils/assets/prost/api.event.rs @@ -9,7 +9,7 @@ pub struct EventNameList { pub struct Event { #[prost(enumeration="EventType", tag="1")] pub name: i32, - #[prost(oneof="event::Payload", tags="2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26")] + #[prost(oneof="event::Payload", tags="2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27")] pub payload: ::core::option::Option, } /// Nested message and enum types in `Event`. @@ -67,6 +67,8 @@ pub mod event { FailedToChangeHostFolderPayload(super::FailedToChangeHostFolderPayload), #[prost(message, tag="26")] PastedTextPayload(super::PastedTextPayload), + #[prost(message, tag="27")] + InterceptedKeyPayload(super::super::key::Key), } } #[allow(clippy::derive_partial_eq_without_eq)] @@ -530,6 +532,7 @@ pub enum EventType { PastedText = 29, ConfigWasWrittenToDisk = 30, BeforeClose = 31, + InterceptedKeyPress = 32, } impl EventType { /// String value of the enum field names used in the ProtoBuf definition. @@ -570,6 +573,7 @@ impl EventType { EventType::PastedText => "PastedText", EventType::ConfigWasWrittenToDisk => "ConfigWasWrittenToDisk", EventType::BeforeClose => "BeforeClose", + EventType::InterceptedKeyPress => "InterceptedKeyPress", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -607,6 +611,7 @@ impl EventType { "PastedText" => Some(Self::PastedText), "ConfigWasWrittenToDisk" => Some(Self::ConfigWasWrittenToDisk), "BeforeClose" => Some(Self::BeforeClose), + "InterceptedKeyPress" => Some(Self::InterceptedKeyPress), _ => None, } } diff --git a/zellij-utils/assets/prost/api.plugin_command.rs b/zellij-utils/assets/prost/api.plugin_command.rs index b7dd7a20..5bdccac9 100644 --- a/zellij-utils/assets/prost/api.plugin_command.rs +++ b/zellij-utils/assets/prost/api.plugin_command.rs @@ -919,6 +919,8 @@ pub enum CommandName { CloseMultiplePanes = 129, FloatMultiplePanes = 130, EmbedMultiplePanes = 131, + InterceptKeyPresses = 132, + ClearKeyPressesIntercepts = 133, } impl CommandName { /// String value of the enum field names used in the ProtoBuf definition. @@ -1059,6 +1061,8 @@ impl CommandName { CommandName::CloseMultiplePanes => "CloseMultiplePanes", CommandName::FloatMultiplePanes => "FloatMultiplePanes", CommandName::EmbedMultiplePanes => "EmbedMultiplePanes", + CommandName::InterceptKeyPresses => "InterceptKeyPresses", + CommandName::ClearKeyPressesIntercepts => "ClearKeyPressesIntercepts", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -1196,6 +1200,8 @@ impl CommandName { "CloseMultiplePanes" => Some(Self::CloseMultiplePanes), "FloatMultiplePanes" => Some(Self::FloatMultiplePanes), "EmbedMultiplePanes" => Some(Self::EmbedMultiplePanes), + "InterceptKeyPresses" => Some(Self::InterceptKeyPresses), + "ClearKeyPressesIntercepts" => Some(Self::ClearKeyPressesIntercepts), _ => None, } } diff --git a/zellij-utils/assets/prost/api.plugin_permission.rs b/zellij-utils/assets/prost/api.plugin_permission.rs index 27eba0d4..4e837373 100644 --- a/zellij-utils/assets/prost/api.plugin_permission.rs +++ b/zellij-utils/assets/prost/api.plugin_permission.rs @@ -12,6 +12,7 @@ pub enum PermissionType { MessageAndLaunchOtherPlugins = 8, Reconfigure = 9, FullHdAccess = 10, + InterceptInput = 11, } impl PermissionType { /// String value of the enum field names used in the ProtoBuf definition. @@ -31,6 +32,7 @@ impl PermissionType { PermissionType::MessageAndLaunchOtherPlugins => "MessageAndLaunchOtherPlugins", PermissionType::Reconfigure => "Reconfigure", PermissionType::FullHdAccess => "FullHdAccess", + PermissionType::InterceptInput => "InterceptInput", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -47,6 +49,7 @@ impl PermissionType { "MessageAndLaunchOtherPlugins" => Some(Self::MessageAndLaunchOtherPlugins), "Reconfigure" => Some(Self::Reconfigure), "FullHdAccess" => Some(Self::FullHdAccess), + "InterceptInput" => Some(Self::InterceptInput), _ => None, } } diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs index 3e888a63..2cceeab8 100644 --- a/zellij-utils/src/data.rs +++ b/zellij-utils/src/data.rs @@ -938,6 +938,7 @@ pub enum Event { PastedText(String), ConfigWasWrittenToDisk, BeforeClose, + InterceptedKeyPress(KeyWithModifier), } #[derive( @@ -969,6 +970,7 @@ pub enum Permission { MessageAndLaunchOtherPlugins, Reconfigure, FullHdAccess, + InterceptInput, } impl PermissionType { @@ -991,6 +993,7 @@ impl PermissionType { }, PermissionType::Reconfigure => "Change Zellij runtime configuration".to_owned(), PermissionType::FullHdAccess => "Full access to the hard-drive".to_owned(), + PermissionType::InterceptInput => "Intercept Input (keyboard & mouse)".to_owned(), } } } @@ -2323,4 +2326,6 @@ pub enum PluginCommand { CloseMultiplePanes(Vec), FloatMultiplePanes(Vec), EmbedMultiplePanes(Vec), + InterceptKeyPresses, + ClearKeyPressesIntercepts, } diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index cf417ad4..dbc9ba60 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -382,6 +382,8 @@ pub enum ScreenContext { EmbedMultiplePanes, TogglePaneInGroup, ToggleGroupMarking, + InterceptKeyPresses, + ClearKeyPressesIntercepts, } /// Stack call representations corresponding to the different types of [`PtyInstruction`]s. diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap index 0a78ce71..e3b5eaa4 100644 --- a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string.snap @@ -146,12 +146,6 @@ keybinds clear-defaults=true { bind "Alt j" { MoveFocus "down"; } bind "Alt k" { MoveFocus "up"; } bind "Alt l" { MoveFocusOrTab "right"; } - bind "Alt m" { - LaunchOrFocusPlugin "zellij:multiple-select" { - floating true - move_to_focused_tab true - } - } bind "Alt n" { NewPane; } bind "Alt o" { MoveTab "right"; } bind "Alt p" { TogglePaneInGroup; } diff --git a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap index 81ca2f2d..c7295555 100644 --- a/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap +++ b/zellij-utils/src/kdl/snapshots/zellij_utils__kdl__bare_config_from_default_assets_to_string_with_comments.snap @@ -146,12 +146,6 @@ keybinds clear-defaults=true { bind "Alt j" { MoveFocus "down"; } bind "Alt k" { MoveFocus "up"; } bind "Alt l" { MoveFocusOrTab "right"; } - bind "Alt m" { - LaunchOrFocusPlugin "zellij:multiple-select" { - floating true - move_to_focused_tab true - } - } bind "Alt n" { NewPane; } bind "Alt o" { MoveTab "right"; } bind "Alt p" { TogglePaneInGroup; } diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto index 9b0e4d2f..760aee0b 100644 --- a/zellij-utils/src/plugin_api/event.proto +++ b/zellij-utils/src/plugin_api/event.proto @@ -55,6 +55,7 @@ enum EventType { PastedText = 29; ConfigWasWrittenToDisk = 30; BeforeClose = 31; + InterceptedKeyPress = 32; } message EventNameList { @@ -89,6 +90,7 @@ message Event { HostFolderChangedPayload host_folder_changed_payload = 24; FailedToChangeHostFolderPayload failed_to_change_host_folder_payload = 25; PastedTextPayload pasted_text_payload = 26; + key.Key intercepted_key_payload = 27; } } diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs index 88c55827..a853e12d 100644 --- a/zellij-utils/src/plugin_api/event.rs +++ b/zellij-utils/src/plugin_api/event.rs @@ -363,6 +363,12 @@ impl TryFrom for Event { None => Ok(Event::BeforeClose), _ => Err("Malformed payload for the BeforeClose Event"), }, + Some(ProtobufEventType::InterceptedKeyPress) => match protobuf_event.payload { + Some(ProtobufEventPayload::KeyPayload(protobuf_key)) => { + Ok(Event::InterceptedKeyPress(protobuf_key.try_into()?)) + }, + _ => Err("Malformed payload for the InterceptedKeyPress Event"), + }, None => Err("Unknown Protobuf Event"), } } @@ -741,6 +747,10 @@ impl TryFrom for ProtobufEvent { name: ProtobufEventType::BeforeClose as i32, payload: None, }), + Event::InterceptedKeyPress(key) => Ok(ProtobufEvent { + name: ProtobufEventType::InterceptedKeyPress as i32, + payload: Some(event::Payload::KeyPayload(key.try_into()?)), + }), } } } @@ -1376,6 +1386,7 @@ impl TryFrom for EventType { ProtobufEventType::PastedText => EventType::PastedText, ProtobufEventType::ConfigWasWrittenToDisk => EventType::ConfigWasWrittenToDisk, ProtobufEventType::BeforeClose => EventType::BeforeClose, + ProtobufEventType::InterceptedKeyPress => EventType::InterceptedKeyPress, }) } } @@ -1416,6 +1427,7 @@ impl TryFrom for ProtobufEventType { EventType::PastedText => ProtobufEventType::PastedText, EventType::ConfigWasWrittenToDisk => ProtobufEventType::ConfigWasWrittenToDisk, EventType::BeforeClose => ProtobufEventType::BeforeClose, + EventType::InterceptedKeyPress => ProtobufEventType::InterceptedKeyPress, }) } } diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto index 3a63b0c8..621b5de6 100644 --- a/zellij-utils/src/plugin_api/plugin_command.proto +++ b/zellij-utils/src/plugin_api/plugin_command.proto @@ -145,6 +145,8 @@ enum CommandName { CloseMultiplePanes = 129; FloatMultiplePanes = 130; EmbedMultiplePanes = 131; + InterceptKeyPresses = 132; + ClearKeyPressesIntercepts = 133; } message PluginCommand { diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs index 833d6270..08a9545e 100644 --- a/zellij-utils/src/plugin_api/plugin_command.rs +++ b/zellij-utils/src/plugin_api/plugin_command.rs @@ -1614,6 +1614,14 @@ impl TryFrom for PluginCommand { }, _ => Err("Mismatched payload for EmbedMultiplePanes"), }, + Some(CommandName::InterceptKeyPresses) => match protobuf_plugin_command.payload { + Some(_) => Err("InterceptKeyPresses should have no payload, found a payload"), + None => Ok(PluginCommand::InterceptKeyPresses), + }, + Some(CommandName::ClearKeyPressesIntercepts) => match protobuf_plugin_command.payload { + Some(_) => Err("ClearKeyPressesIntercepts should have no payload, found a payload"), + None => Ok(PluginCommand::ClearKeyPressesIntercepts), + }, None => Err("Unrecognized plugin command"), } } @@ -2684,6 +2692,14 @@ impl TryFrom for ProtobufPluginCommand { }, )), }), + PluginCommand::InterceptKeyPresses => Ok(ProtobufPluginCommand { + name: CommandName::InterceptKeyPresses as i32, + payload: None, + }), + PluginCommand::ClearKeyPressesIntercepts => Ok(ProtobufPluginCommand { + name: CommandName::ClearKeyPressesIntercepts as i32, + payload: None, + }), } } } diff --git a/zellij-utils/src/plugin_api/plugin_permission.proto b/zellij-utils/src/plugin_api/plugin_permission.proto index 4f1f90f9..72c5b0f9 100644 --- a/zellij-utils/src/plugin_api/plugin_permission.proto +++ b/zellij-utils/src/plugin_api/plugin_permission.proto @@ -14,4 +14,5 @@ enum PermissionType { MessageAndLaunchOtherPlugins = 8; Reconfigure = 9; FullHdAccess = 10; + InterceptInput = 11; } diff --git a/zellij-utils/src/plugin_api/plugin_permission.rs b/zellij-utils/src/plugin_api/plugin_permission.rs index 5b6a831f..ad64b499 100644 --- a/zellij-utils/src/plugin_api/plugin_permission.rs +++ b/zellij-utils/src/plugin_api/plugin_permission.rs @@ -26,6 +26,7 @@ impl TryFrom for PermissionType { }, ProtobufPermissionType::Reconfigure => Ok(PermissionType::Reconfigure), ProtobufPermissionType::FullHdAccess => Ok(PermissionType::FullHdAccess), + ProtobufPermissionType::InterceptInput => Ok(PermissionType::InterceptInput), } } } @@ -53,6 +54,7 @@ impl TryFrom for ProtobufPermissionType { }, PermissionType::Reconfigure => Ok(ProtobufPermissionType::Reconfigure), PermissionType::FullHdAccess => Ok(ProtobufPermissionType::FullHdAccess), + PermissionType::InterceptInput => Ok(ProtobufPermissionType::InterceptInput), } } } diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap index ca465e22..8a09cae9 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__default_config_with_no_cli_arguments.snap @@ -210,35 +210,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -758,35 +729,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1264,35 +1206,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1912,35 +1825,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2450,35 +2334,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2854,35 +2709,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3330,35 +3156,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3759,35 +3556,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4141,35 +3909,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4577,35 +4316,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5090,35 +4800,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5485,35 +5166,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -6045,35 +5697,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap index 3af974e0..e4ac2827 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_env_vars_override_config_env_vars.snap @@ -210,35 +210,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -758,35 +729,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1264,35 +1206,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1912,35 +1825,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2450,35 +2334,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2854,35 +2709,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3330,35 +3156,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3759,35 +3556,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4141,35 +3909,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4577,35 +4316,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5090,35 +4800,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5485,35 +5166,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -6045,35 +5697,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap index 5281896f..0f330251 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_themes_override_config_themes.snap @@ -210,35 +210,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -758,35 +729,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1264,35 +1206,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1912,35 +1825,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2450,35 +2334,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2854,35 +2709,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3330,35 +3156,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3759,35 +3556,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4141,35 +3909,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4577,35 +4316,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5090,35 +4800,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5485,35 +5166,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -6045,35 +5697,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', diff --git a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap index a56b840e..263c68ee 100644 --- a/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap +++ b/zellij-utils/src/snapshots/zellij_utils__setup__setup_test__layout_ui_config_overrides_config_ui_config.snap @@ -210,35 +210,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -758,35 +729,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1264,35 +1206,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -1912,35 +1825,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2450,35 +2334,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -2854,35 +2709,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3330,35 +3156,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -3759,35 +3556,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4141,35 +3909,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -4577,35 +4316,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5090,35 +4800,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -5485,35 +5166,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n', @@ -6045,35 +5697,6 @@ Config { Right, ), ], - KeyWithModifier { - bare_key: Char( - 'm', - ), - key_modifiers: { - Alt, - }, - }: [ - LaunchOrFocusPlugin( - RunPlugin( - RunPlugin { - _allow_exec_host_cmd: false, - location: Zellij( - PluginTag( - "multiple-select", - ), - ), - configuration: PluginUserConfiguration( - {}, - ), - initial_cwd: None, - }, - ), - true, - true, - false, - false, - ), - ], KeyWithModifier { bare_key: Char( 'n',