aboutsummaryrefslogtreecommitdiffstats
path: root/default-plugins/compact-bar/src
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2025-06-03 17:15:32 +0200
committerGitHub <noreply@github.com>2025-06-03 17:15:32 +0200
commita9f8bbcd197c8d14832fc1ab1fbe4d4111a2014d (patch)
tree6d354fdd36cf534d73e0cb81a7cacd3fedc1ebb9 /default-plugins/compact-bar/src
parentdocs(changelog): theme fixes (diff)
downloadsl0ppij-a9f8bbcd197c8d14832fc1ab1fbe4d4111a2014d.tar.gz
sl0ppij-a9f8bbcd197c8d14832fc1ab1fbe4d4111a2014d.tar.xz
sl0ppij-a9f8bbcd197c8d14832fc1ab1fbe4d4111a2014d.zip
feat(ux): improve multiple select (#4221)
* intercept/clear-intercept key APIs * allow opening a pinned unfocused floating pane * rework plugin * improve some apis * fix tests * tests for pane groups * more exact placement and tests * plugin command permission and cleanup * improve some multiselect ux * improve plugin ui * remove old status indicator * allow moving plugin out of the way * style(fmt): rustfmt * update plugins * remove old keybinding * cleanups * fix: only rename pane if needed * changelog and some cleanups * style(fmt): rustfmt
Diffstat (limited to 'default-plugins/compact-bar/src')
-rw-r--r--default-plugins/compact-bar/src/line.rs300
-rw-r--r--default-plugins/compact-bar/src/main.rs27
2 files changed, 10 insertions, 317 deletions
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<String>,
is_swap_layout_dirty: bool,
- mode_info: &ModeInfo,
- grouped_pane_count: Option<usize>,
) -> Vec<LinePart> {
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<LinePart> {
- 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<KeyWithModifier> = multiple_select_key
- .iter()
- .map(|k| k.strip_common_modifiers(&common_modifiers))
- .collect();
- let pane_group_toggle_key: Vec<KeyWithModifier> = pane_group_toggle_key
- .iter()
- .map(|k| k.strip_common_modifiers(&common_modifiers))
- .collect();
- let group_mark_toggle_key: Vec<KeyWithModifier> = 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::<Vec<_>>()
- .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<Action>)]) -> Vec<KeyWithModifier> {
- 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: &[Action],
-) -> Vec<KeyWithModifier> {
- 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<KeyModifier> {
- 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<LinePart>,
text_copy_destination: Option<CopyDestination>,
display_system_clipboard_failure: bool,
- own_client_id: Option<ClientId>,
- grouped_panes_count: Option<usize>,
}
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