diff --git a/default-plugins/compact-bar/src/main.rs b/default-plugins/compact-bar/src/main.rs index 18c9f12b..a7a19bd0 100644 --- a/default-plugins/compact-bar/src/main.rs +++ b/default-plugins/compact-bar/src/main.rs @@ -31,7 +31,7 @@ static ARROW_SEPARATOR: &str = ""; register_plugin!(State); impl ZellijPlugin for State { - fn load(&mut self, configuration: BTreeMap) { + fn load(&mut self, _configuration: BTreeMap) { set_selectable(false); subscribe(&[ EventType::TabUpdate, diff --git a/default-plugins/session-manager/src/ui/components.rs b/default-plugins/session-manager/src/ui/components.rs index 6b606589..72aa2181 100644 --- a/default-plugins/session-manager/src/ui/components.rs +++ b/default-plugins/session-manager/src/ui/components.rs @@ -294,7 +294,7 @@ impl LineToRender { } pub fn make_selected(&mut self) { self.is_selected = true; - match self.colors.palette.gray { + match self.colors.palette.bg { PaletteColor::EightBit(byte) => { self.line = format!( "\u{1b}[48;5;{byte}m\u{1b}[K\r\u{1b}[48;5;{byte}m{}", @@ -303,7 +303,7 @@ impl LineToRender { }, PaletteColor::Rgb((r, g, b)) => { self.line = format!( - "\u{1b}[48;2;{};{};{}m\u{1b}[K\r\u{1b}[48;5;{};{};{}m{}", + "\u{1b}[48;2;{};{};{}m\u{1b}[K\r\u{1b}[48;2;{};{};{}m{}", r, g, b, r, g, b, self.line ); }, diff --git a/default-plugins/status-bar/src/first_line.rs b/default-plugins/status-bar/src/first_line.rs index 183aa64f..23a6d586 100644 --- a/default-plugins/status-bar/src/first_line.rs +++ b/default-plugins/status-bar/src/first_line.rs @@ -8,14 +8,13 @@ use crate::{ }; use crate::{ColoredElements, LinePart}; -#[derive(Debug, Clone, Copy)] struct KeyShortcut { mode: KeyMode, - pub action: KeyAction, + action: KeyAction, key: Option, } -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(PartialEq)] enum KeyAction { Lock, Pane, @@ -28,7 +27,6 @@ enum KeyAction { Tmux, } -#[derive(Debug, Clone, Copy)] enum KeyMode { Unselected, UnselectedAlternate, @@ -36,20 +34,6 @@ enum KeyMode { Disabled, } -fn letter_shortcut(key: &Key, with_prefix: bool) -> String { - if with_prefix { - format!("{}", key) - } else { - match key { - Key::F(c) => format!("{}", c), - Key::Ctrl(c) => format!("{}", c), - Key::Char(_) => format!("{}", key), - Key::Alt(c) => format!("{}", c), - _ => String::from("??"), - } - } -} - impl KeyShortcut { pub fn new(mode: KeyMode, action: KeyAction, key: Option) -> Self { KeyShortcut { mode, action, key } @@ -73,7 +57,17 @@ impl KeyShortcut { Some(k) => k, None => return String::from("?"), }; - letter_shortcut(&key, with_prefix) + if with_prefix { + format!("{}", key) + } else { + match key { + Key::F(c) => format!("{}", c), + Key::Ctrl(c) => format!("{}", c), + Key::Char(_) => format!("{}", key), + Key::Alt(c) => format!("{}", c), + _ => String::from("??"), + } + } } } @@ -202,58 +196,6 @@ fn short_mode_shortcut( } } -fn short_key_indicators( - max_len: usize, - keys: &[KeyShortcut], - palette: ColoredElements, - separator: &str, - mode_info: &ModeInfo, - no_super: bool, -) -> LinePart { - let mut line_part = if no_super { - LinePart::default() - } else { - superkey(palette, separator, mode_info) - }; - let shared_super = if no_super { true } else { line_part.len > 0 }; - for ctrl_key in keys { - let line_empty = line_part.len == 0; - let key = short_mode_shortcut(ctrl_key, palette, separator, shared_super, line_empty); - line_part.part = format!("{}{}", line_part.part, key.part); - line_part.len += key.len; - } - if line_part.len < max_len { - return line_part; - } - - // Shortened doesn't fit, print nothing - line_part = LinePart::default(); - line_part -} - -fn full_key_indicators( - keys: &[KeyShortcut], - palette: ColoredElements, - separator: &str, - mode_info: &ModeInfo, - no_super: bool, -) -> LinePart { - // Print full-width hints - let mut line_part = if no_super { - LinePart::default() - } else { - superkey(palette, separator, mode_info) - }; - let shared_super = if no_super { true } else { line_part.len > 0 }; - for ctrl_key in keys { - let line_empty = line_part.len == 0; - let key = long_mode_shortcut(ctrl_key, palette, separator, shared_super, line_empty); - line_part.part = format!("{}{}", line_part.part, key.part); - line_part.len += key.len; - } - line_part -} - fn key_indicators( max_len: usize, keys: &[KeyShortcut], @@ -460,111 +402,6 @@ pub fn superkey(palette: ColoredElements, separator: &str, mode_info: &ModeInfo) } } -fn standby_mode_shortcut_key(help: &ModeInfo) -> Key { - let binds = &help.get_mode_keybinds(); - match help.mode { - InputMode::Locked => to_char(action_key( - binds, - &[Action::SwitchToMode(InputMode::Normal)], - )), - _ => to_char(action_key( - binds, - &[Action::SwitchToMode(InputMode::Locked)], - )), - } - .unwrap_or(Key::Char('?')) -} - -fn standby_mode_ui_indication( - has_shared_super: bool, - standby_mode: &InputMode, - standby_mode_shortcut_key: Key, - colored_elements: ColoredElements, - separator: &str, -) -> LinePart { - let mut line_part = LinePart::default(); - let standby_mode_shortcut = standby_mode_single_letter_selected( - has_shared_super, - standby_mode_shortcut_key, - colored_elements, - separator, - ); - // standby mode text hint - let key_shortcut = KeyShortcut::new( - KeyMode::Unselected, - input_mode_to_key_action(&standby_mode), - None, - ); - let styled_text = colored_elements - .unselected - .styled_text - .paint(format!(" {} ", key_shortcut.full_text())); - let suffix_separator = colored_elements - .unselected - .suffix_separator - .paint(separator); - let standby_mode_text = LinePart { - part: ANSIStrings(&[styled_text, suffix_separator]).to_string(), - len: key_shortcut.full_text().chars().count() + separator.chars().count() + 2, // 2 padding - }; - line_part.part = format!("{}{}", line_part.part, standby_mode_shortcut.part); - line_part.len += standby_mode_shortcut.len; - line_part.part = format!("{}{}", line_part.part, standby_mode_text.part); - line_part.len += standby_mode_text.len; - line_part -} - -fn standby_mode_single_letter_unselected( - has_shared_super: bool, - shortcut_key: Key, - palette: ColoredElements, - separator: &str, -) -> LinePart { - let prefix_separator = palette.unselected.prefix_separator.paint(separator); - let char_shortcut = palette.unselected.char_shortcut.paint(format!( - " {} ", - letter_shortcut(&shortcut_key, has_shared_super) - )); - let suffix_separator = palette.unselected.suffix_separator.paint(separator); - let len = prefix_separator.chars().count() - + char_shortcut.chars().count() - + suffix_separator.chars().count(); - LinePart { - part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(), - len, - } -} - -fn standby_mode_single_letter_selected( - has_shared_super: bool, - shortcut_key: Key, - palette: ColoredElements, - separator: &str, -) -> LinePart { - let prefix_separator = palette - .selected_standby_shortcut - .prefix_separator - .paint(separator); - let char_shortcut = palette - .selected_standby_shortcut - .char_shortcut - .paint(format!( - " {} ", - letter_shortcut(&shortcut_key, has_shared_super) - )); - let suffix_separator = palette - .selected_standby_shortcut - .suffix_separator - .paint(separator); - let len = prefix_separator.chars().count() - + char_shortcut.chars().count() - + suffix_separator.chars().count(); - LinePart { - part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(), - len, - } -} - pub fn to_char(kv: Vec) -> Option { let key = kv .iter() @@ -582,19 +419,6 @@ pub fn to_char(kv: Vec) -> Option { key.cloned() } -fn input_mode_to_key_action(input_mode: &InputMode) -> KeyAction { - match input_mode { - InputMode::Normal | InputMode::Prompt | InputMode::Tmux => KeyAction::Lock, - InputMode::Locked => KeyAction::Lock, - InputMode::Pane | InputMode::RenamePane => KeyAction::Pane, - InputMode::Tab | InputMode::RenameTab => KeyAction::Tab, - InputMode::Resize => KeyAction::Resize, - InputMode::Move => KeyAction::Move, - InputMode::Scroll | InputMode::Search | InputMode::EnterSearch => KeyAction::Search, - InputMode::Session => KeyAction::Session, - } -} - /// Get the [`KeyShortcut`] for a specific [`InputMode`]. /// /// Iterates over the contents of `shortcuts` to find the [`KeyShortcut`] with the [`KeyAction`] @@ -625,8 +449,7 @@ fn get_key_shortcut_for_mode<'a>( None } -pub fn first_line_supermode( - standby_mode: &InputMode, +pub fn first_line( help: &ModeInfo, tab_info: Option<&TabInfo>, max_len: usize, @@ -634,129 +457,9 @@ pub fn first_line_supermode( ) -> LinePart { let supports_arrow_fonts = !help.capabilities.arrow_fonts; let colored_elements = color_elements(help.style.colors, !supports_arrow_fonts); - - let standby_mode_shortcut_key = standby_mode_shortcut_key(&help); - - let mut line = superkey(colored_elements, separator, help); - let has_shared_super = line.len == 0; - let max_len_without_superkey = max_len.saturating_sub(line.len); - let mut append_to_line = |line_part_to_append: LinePart| { - line.part = format!("{}{}", line.part, line_part_to_append.part); - line.len += line_part_to_append.len; - }; - match help.mode { - InputMode::Locked => { - let standby_mode_shortcut = standby_mode_single_letter_unselected( - has_shared_super, - standby_mode_shortcut_key, - colored_elements, - separator, - ); - append_to_line(standby_mode_shortcut); - line - }, - _ => { - let mut default_keys = generate_default_keys(help); - default_keys.remove(0); // remove locked mode which is not relevant to the supermode ui - - if let Some(position) = default_keys - .iter() - .position(|d| d.action == input_mode_to_key_action(standby_mode)) - { - let standby_mode_ui_ribbon = standby_mode_ui_indication( - has_shared_super, - &standby_mode, - standby_mode_shortcut_key, - colored_elements, - separator, - ); - let first_keybinds: Vec = - default_keys.iter().cloned().take(position).collect(); - let second_keybinds: Vec = - default_keys.iter().cloned().skip(position + 1).collect(); - let first_key_indicators = - full_key_indicators(&first_keybinds, colored_elements, separator, help, true); - let second_key_indicators = - full_key_indicators(&second_keybinds, colored_elements, separator, help, true); - - if first_key_indicators.len + standby_mode_ui_ribbon.len + second_key_indicators.len - < max_len_without_superkey - { - append_to_line(first_key_indicators); - append_to_line(standby_mode_ui_ribbon); - append_to_line(second_key_indicators); - } else { - let length_of_each_half = - max_len_without_superkey.saturating_sub(standby_mode_ui_ribbon.len) / 2; - let first_key_indicators = short_key_indicators( - length_of_each_half, - &first_keybinds, - colored_elements, - separator, - help, - true, - ); - let second_key_indicators = short_key_indicators( - length_of_each_half, - &second_keybinds, - colored_elements, - separator, - help, - true, - ); - append_to_line(first_key_indicators); - append_to_line(standby_mode_ui_ribbon); - append_to_line(second_key_indicators); - } - if line.len < max_len { - if let Some(tab_info) = tab_info { - let remaining_space = max_len.saturating_sub(line.len); - line.append(&swap_layout_status_and_padding( - &tab_info, - remaining_space, - separator, - colored_elements, - help, - )); - } - } - } - line - }, - } -} - -fn swap_layout_status_and_padding( - tab_info: &TabInfo, - mut remaining_space: usize, - separator: &str, - colored_elements: ColoredElements, - help: &ModeInfo, -) -> LinePart { - let mut line = LinePart::default(); - if let Some(swap_layout_status) = swap_layout_status( - remaining_space, - &tab_info.active_swap_layout_name, - tab_info.is_swap_layout_dirty, - help, - colored_elements, - &help.style.colors, - separator, - ) { - remaining_space -= swap_layout_status.len; - for _ in 0..remaining_space { - line.part - .push_str(&ANSIStrings(&[colored_elements.superkey_prefix.paint(" ")]).to_string()); - line.len += 1; - } - line.append(&swap_layout_status); - } - line -} - -fn generate_default_keys(help: &ModeInfo) -> Vec { let binds = &help.get_mode_keybinds(); - vec![ + // Unselect all by default + let mut default_keys = vec![ KeyShortcut::new( KeyMode::Unselected, KeyAction::Lock, @@ -809,20 +512,7 @@ fn generate_default_keys(help: &ModeInfo) -> Vec { KeyAction::Quit, to_char(action_key(binds, &[Action::Quit])), ), - ] -} - -pub fn first_line( - help: &ModeInfo, - tab_info: Option<&TabInfo>, - max_len: usize, - separator: &str, -) -> LinePart { - let supports_arrow_fonts = !help.capabilities.arrow_fonts; - let colored_elements = color_elements(help.style.colors, !supports_arrow_fonts); - let binds = &help.get_mode_keybinds(); - // Unselect all by default - let mut default_keys = generate_default_keys(help); // TODO: check that this still works + ]; if let Some(key_shortcut) = get_key_shortcut_for_mode(&mut default_keys, &help.mode) { key_shortcut.mode = KeyMode::Selected; @@ -849,14 +539,25 @@ pub fn first_line( key_indicators(max_len, &default_keys, colored_elements, separator, help); if key_indicators.len < max_len { if let Some(tab_info) = tab_info { - let remaining_space = max_len - key_indicators.len; - key_indicators.append(&swap_layout_status_and_padding( - &tab_info, + let mut remaining_space = max_len - key_indicators.len; + if let Some(swap_layout_status) = swap_layout_status( remaining_space, - separator, - colored_elements, + &tab_info.active_swap_layout_name, + tab_info.is_swap_layout_dirty, help, - )); + colored_elements, + &help.style.colors, + separator, + ) { + remaining_space -= swap_layout_status.len; + for _ in 0..remaining_space { + key_indicators.part.push_str( + &ANSIStrings(&[colored_elements.superkey_prefix.paint(" ")]).to_string(), + ); + key_indicators.len += 1; + } + key_indicators.append(&swap_layout_status); + } } } key_indicators diff --git a/default-plugins/status-bar/src/main.rs b/default-plugins/status-bar/src/main.rs index d768b35e..2910d678 100644 --- a/default-plugins/status-bar/src/main.rs +++ b/default-plugins/status-bar/src/main.rs @@ -14,9 +14,10 @@ use zellij_tile::prelude::actions::Action; use zellij_tile::prelude::*; use zellij_tile_utils::{palette_match, style}; -use first_line::{first_line, first_line_supermode}; +use first_line::first_line; use second_line::{ - floating_panes_are_visible, fullscreen_panes_to_hide, keybinds, system_clipboard_error, + floating_panes_are_visible, fullscreen_panes_to_hide, keybinds, + locked_floating_panes_are_visible, locked_fullscreen_panes_to_hide, system_clipboard_error, text_copied_hint, }; use tip::utils::get_cached_tip_name; @@ -34,10 +35,6 @@ struct State { mode_info: ModeInfo, text_copy_destination: Option, display_system_clipboard_failure: bool, - - supermode: bool, - standby_mode: InputMode, - current_mode: InputMode, } register_plugin!(State); @@ -64,7 +61,6 @@ impl Display for LinePart { #[derive(Clone, Copy)] pub struct ColoredElements { pub selected: SegmentStyle, - pub selected_standby_shortcut: SegmentStyle, pub unselected: SegmentStyle, pub unselected_alternate: SegmentStyle, pub disabled: SegmentStyle, @@ -114,14 +110,6 @@ fn color_elements(palette: Palette, different_color_alternates: bool) -> Colored styled_text: style!(background, palette.green).bold(), suffix_separator: style!(palette.green, background).bold(), }, - selected_standby_shortcut: SegmentStyle { - prefix_separator: style!(background, palette.green), - char_left_separator: style!(background, palette.green).bold(), - char_shortcut: style!(palette.red, palette.green).bold(), - char_right_separator: style!(background, palette.green).bold(), - styled_text: style!(background, palette.green).bold(), - suffix_separator: style!(palette.green, palette.fg).bold(), - }, unselected: SegmentStyle { prefix_separator: style!(background, palette.fg), char_left_separator: style!(background, palette.fg).bold(), @@ -158,14 +146,6 @@ fn color_elements(palette: Palette, different_color_alternates: bool) -> Colored styled_text: style!(background, palette.green).bold(), suffix_separator: style!(palette.green, background).bold(), }, - selected_standby_shortcut: SegmentStyle { - prefix_separator: style!(background, palette.green), - char_left_separator: style!(background, palette.green).bold(), - char_shortcut: style!(palette.red, palette.green).bold(), - char_right_separator: style!(background, palette.green).bold(), - styled_text: style!(background, palette.green).bold(), - suffix_separator: style!(palette.green, palette.fg).bold(), - }, unselected: SegmentStyle { prefix_separator: style!(background, palette.fg), char_left_separator: style!(background, palette.fg).bold(), @@ -197,7 +177,7 @@ fn color_elements(palette: Palette, different_color_alternates: bool) -> Colored } impl ZellijPlugin for State { - fn load(&mut self, configuration: BTreeMap) { + fn load(&mut self, _configuration: BTreeMap) { // TODO: Should be able to choose whether to use the cache through config. self.tip_name = get_cached_tip_name(); set_selectable(false); @@ -208,47 +188,12 @@ impl ZellijPlugin for State { EventType::InputReceived, EventType::SystemClipboardFailure, ]); - self.supermode = configuration - .get("supermode") - .and_then(|s| s.trim().parse().ok()) - .unwrap_or(false); - self.standby_mode = InputMode::Pane; - if self.supermode { - switch_to_input_mode(&InputMode::Locked); // supermode should start locked (TODO: only - // once per app load, let's not do this on - // each tab loading) - } } fn update(&mut self, event: Event) -> bool { let mut should_render = false; match event { Event::ModeUpdate(mode_info) => { - if self.supermode { - // supermode is a "sticky" mode that is not Normal or Locked - // using this configuration, we default to Locked mode in order to avoid key - // collisions with terminal applications - // whenever the user switches away from locked mode, we make sure to place them - // in the standby mode - // whenever the user switches to a mode that is not locked or normal, we set - // that mode as the standby mode - // whenever the user switches away from the standby mode, we palce them in - // normal mode - if mode_info.mode == InputMode::Normal && self.current_mode == InputMode::Locked - { - switch_to_input_mode(&self.standby_mode); - } else if mode_info.mode == InputMode::Normal - && self.current_mode == self.standby_mode - { - switch_to_input_mode(&InputMode::Locked); - } else if mode_info.mode != InputMode::Locked - && mode_info.mode != InputMode::Normal - { - self.standby_mode = mode_info.mode; - } - self.current_mode = mode_info.mode; - } - if self.mode_info != mode_info { should_render = true; } @@ -300,17 +245,7 @@ impl ZellijPlugin for State { }; let active_tab = self.tabs.iter().find(|t| t.active); - let first_line = if self.supermode { - first_line_supermode( - &self.standby_mode, - &self.mode_info, - active_tab, - cols, - separator, - ) - } else { - first_line(&self.mode_info, active_tab, cols, separator) - }; + let first_line = first_line(&self.mode_info, active_tab, cols, separator); let second_line = self.second_line(cols); let background = match self.mode_info.style.colors.theme_hue { @@ -362,7 +297,11 @@ impl State { } else if let Some(active_tab) = active_tab { if active_tab.is_fullscreen_active { match self.mode_info.mode { - InputMode::Normal | InputMode::Locked => fullscreen_panes_to_hide( + InputMode::Normal => fullscreen_panes_to_hide( + &self.mode_info.style.colors, + active_tab.panes_to_hide, + ), + InputMode::Locked => locked_fullscreen_panes_to_hide( &self.mode_info.style.colors, active_tab.panes_to_hide, ), @@ -370,8 +309,9 @@ impl State { } } else if active_tab.are_floating_panes_visible { match self.mode_info.mode { - InputMode::Normal | InputMode::Locked => { - floating_panes_are_visible(&self.mode_info) + InputMode::Normal => floating_panes_are_visible(&self.mode_info), + InputMode::Locked => { + locked_floating_panes_are_visible(&self.mode_info.style.colors) }, _ => keybinds(&self.mode_info, &self.tip_name, cols), } diff --git a/default-plugins/status-bar/src/second_line.rs b/default-plugins/status-bar/src/second_line.rs index e3923174..4376616a 100644 --- a/default-plugins/status-bar/src/second_line.rs +++ b/default-plugins/status-bar/src/second_line.rs @@ -45,6 +45,20 @@ fn full_length_shortcut( } } +fn locked_interface_indication(palette: Palette) -> LinePart { + let locked_text = " -- INTERFACE LOCKED -- "; + let locked_text_len = locked_text.chars().count(); + let text_color = palette_match!(match palette.theme_hue { + ThemeHue::Dark => palette.white, + ThemeHue::Light => palette.black, + }); + let locked_styled_text = Style::new().fg(text_color).bold().paint(locked_text); + LinePart { + part: locked_styled_text.to_string(), + len: locked_text_len, + } +} + fn add_shortcut(help: &ModeInfo, linepart: &LinePart, text: &str, keys: Vec) -> LinePart { let shortcut = if linepart.len == 0 { full_length_shortcut(true, keys, text, help.style.colors) @@ -166,12 +180,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { (s("Rename"), s("Rename"), action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])), (s("Sync"), s("Sync"), action_key(&km, &[A::ToggleActiveSyncTab, TO_NORMAL])), - (s("Break pane to new tab"), s("Break"), action_key(&km, &[A::BreakPane, TO_NORMAL])), - (s("Break pane to next/prev tab"), s("Break next/prev"), - action_key_group(&km, &[ - &[A::BreakPaneLeft, TO_NORMAL], - &[A::BreakPaneRight, TO_NORMAL] - ])), + (s("Toggle"), s("Toggle"), action_key(&km, &[A::ToggleTab])), (s("Select pane"), s("Select"), to_normal_key), ]} else if mi.mode == IM::Resize { vec![ (s("Increase/Decrease size"), s("Increase/Decrease"), @@ -231,6 +240,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { action_key(&km, &[A::SearchToggleOption(SOpt::WholeWord)])), ]} else if mi.mode == IM::Session { vec![ (s("Detach"), s("Detach"), action_key(&km, &[Action::Detach])), + (s("Session Manager"), s("Manager"), action_key(&km, &[A::LaunchOrFocusPlugin(Default::default(), true), TO_NORMAL])), // not entirely accurate (s("Select pane"), s("Select"), to_normal_key), ]} else if mi.mode == IM::Tmux { vec![ (s("Move focus"), s("Move"), action_key_group(&km, &[ @@ -255,7 +265,8 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec)> { fn full_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart { match help.mode { - InputMode::Normal | InputMode::Locked => tip(help), + InputMode::Normal => tip(help), + InputMode::Locked => locked_interface_indication(help.style.colors), _ => full_shortcut_list_nonstandard_mode(help), } } @@ -272,7 +283,8 @@ fn shortened_shortcut_list_nonstandard_mode(help: &ModeInfo) -> LinePart { fn shortened_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart { match help.mode { - InputMode::Normal | InputMode::Locked => tip(help), + InputMode::Normal => tip(help), + InputMode::Locked => locked_interface_indication(help.style.colors), _ => shortened_shortcut_list_nonstandard_mode(help), } } @@ -295,7 +307,7 @@ fn best_effort_shortcut_list_nonstandard_mode(help: &ModeInfo, max_len: usize) - fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> LinePart { match help.mode { - InputMode::Normal | InputMode::Locked => { + InputMode::Normal => { let line_part = tip(help); if line_part.len <= max_len { line_part @@ -303,6 +315,14 @@ fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> Lin LinePart::default() } }, + InputMode::Locked => { + let line_part = locked_interface_indication(help.style.colors); + if line_part.len <= max_len { + line_part + } else { + LinePart::default() + } + }, _ => best_effort_shortcut_list_nonstandard_mode(help, max_len), } } @@ -447,6 +467,68 @@ pub fn floating_panes_are_visible(mode_info: &ModeInfo) -> LinePart { } } +pub fn locked_fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> LinePart { + let text_color = palette_match!(match palette.theme_hue { + ThemeHue::Dark => palette.white, + ThemeHue::Light => palette.black, + }); + let green_color = palette_match!(palette.green); + let orange_color = palette_match!(palette.orange); + let locked_text = " -- INTERFACE LOCKED -- "; + let shortcut_left_separator = Style::new().fg(text_color).bold().paint(" ("); + let shortcut_right_separator = Style::new().fg(text_color).bold().paint("): "); + let fullscreen = "FULLSCREEN"; + let puls = "+ "; + let panes = panes_to_hide.to_string(); + let hide = " hidden panes"; + let len = locked_text.chars().count() + + fullscreen.chars().count() + + puls.chars().count() + + panes.chars().count() + + hide.chars().count() + + 5; // 3 for ():'s around shortcut, 2 for the space + LinePart { + part: format!( + "{}{}{}{}{}{}{}", + Style::new().fg(text_color).bold().paint(locked_text), + shortcut_left_separator, + Style::new().fg(orange_color).bold().paint(fullscreen), + shortcut_right_separator, + Style::new().fg(text_color).bold().paint(puls), + Style::new().fg(green_color).bold().paint(panes), + Style::new().fg(text_color).bold().paint(hide) + ), + len, + } +} + +pub fn locked_floating_panes_are_visible(palette: &Palette) -> LinePart { + let white_color = match palette.white { + PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), + PaletteColor::EightBit(color) => Fixed(color), + }; + let orange_color = match palette.orange { + PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), + PaletteColor::EightBit(color) => Fixed(color), + }; + let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" ("); + let shortcut_right_separator = Style::new().fg(white_color).bold().paint(")"); + let locked_text = " -- INTERFACE LOCKED -- "; + let floating_panes = "FLOATING PANES VISIBLE"; + + let len = locked_text.chars().count() + floating_panes.chars().count(); + LinePart { + part: format!( + "{}{}{}{}", + Style::new().fg(white_color).bold().paint(locked_text), + shortcut_left_separator, + Style::new().fg(orange_color).bold().paint(floating_panes), + shortcut_right_separator, + ), + len, + } +} + #[cfg(test)] /// Unit tests. /// @@ -581,6 +663,7 @@ mod tests { assert_eq!(ret, " / Ctrl + Foobar"); } + //pub fn keybinds(help: &ModeInfo, tip_name: &str, max_width: usize) -> LinePart { #[test] // Note how it leaves out elements that don't exist! @@ -665,9 +748,6 @@ mod tests { let ret = keybinds(&mode_info, "quicknav", 500); let ret = unstyle(ret); - assert_eq!( - ret, - " New / Ctrl + Change Focus / Close / Toggle Fullscreen" - ); + assert_eq!(ret, " New / Ctrl + Change Focus / Close / Toggle Fullscreen"); } } diff --git a/default-plugins/status-bar/src/tip/data/compact_layout.rs b/default-plugins/status-bar/src/tip/data/compact_layout.rs index 13ee18bd..77dec8a6 100644 --- a/default-plugins/status-bar/src/tip/data/compact_layout.rs +++ b/default-plugins/status-bar/src/tip/data/compact_layout.rs @@ -77,7 +77,7 @@ pub fn compact_layout_short(help: &ModeInfo) -> LinePart { fn add_keybinds(help: &ModeInfo) -> Vec { let to_pane = action_key( - &help.get_keybinds_for_mode(InputMode::Normal), + &help.get_mode_keybinds(), &[Action::SwitchToMode(InputMode::Pane)], ); let pane_frames = action_key( diff --git a/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs b/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs index 9ff210ed..ebd944b7 100644 --- a/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs +++ b/default-plugins/status-bar/src/tip/data/edit_scrollbuffer.rs @@ -67,7 +67,7 @@ pub fn edit_scrollbuffer_short(help: &ModeInfo) -> LinePart { fn add_keybinds(help: &ModeInfo) -> Vec { let to_pane = action_key( - &help.get_keybinds_for_mode(InputMode::Normal), + &help.get_mode_keybinds(), &[Action::SwitchToMode(InputMode::Scroll)], ); let edit_buffer = action_key( diff --git a/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs b/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs index 17439c4b..4bf4a143 100644 --- a/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs +++ b/default-plugins/status-bar/src/tip/data/floating_panes_mouse.rs @@ -46,7 +46,7 @@ pub fn floating_panes_mouse_short(help: &ModeInfo) -> LinePart { fn add_keybinds(help: &ModeInfo) -> Vec { let to_pane = action_key( - &help.get_keybinds_for_mode(InputMode::Normal), + &help.get_mode_keybinds(), &[Action::SwitchToMode(InputMode::Pane)], ); let floating_toggle = action_key( diff --git a/default-plugins/status-bar/src/tip/data/quicknav.rs b/default-plugins/status-bar/src/tip/data/quicknav.rs index fe118f2c..318fe702 100644 --- a/default-plugins/status-bar/src/tip/data/quicknav.rs +++ b/default-plugins/status-bar/src/tip/data/quicknav.rs @@ -61,7 +61,7 @@ struct Keygroups<'a> { } fn add_keybinds(help: &ModeInfo) -> Keygroups { - let normal_keymap = help.get_keybinds_for_mode(InputMode::Normal); + let normal_keymap = help.get_mode_keybinds(); let new_pane_keys = action_key(&normal_keymap, &[Action::NewPane(None, None)]); let new_pane = if new_pane_keys.is_empty() { vec![Style::new().bold().paint("UNBOUND")] diff --git a/default-plugins/status-bar/src/tip/data/sync_tab.rs b/default-plugins/status-bar/src/tip/data/sync_tab.rs index 71a4ed50..486e2aa2 100644 --- a/default-plugins/status-bar/src/tip/data/sync_tab.rs +++ b/default-plugins/status-bar/src/tip/data/sync_tab.rs @@ -45,7 +45,7 @@ pub fn sync_tab_short(help: &ModeInfo) -> LinePart { fn add_keybinds(help: &ModeInfo) -> Vec { let to_tab = action_key( - &help.get_keybinds_for_mode(InputMode::Normal), + &help.get_mode_keybinds(), &[Action::SwitchToMode(InputMode::Tab)], ); let sync_tabs = action_key( diff --git a/default-plugins/strider/src/main.rs b/default-plugins/strider/src/main.rs index 3d4c94a9..598bf61d 100644 --- a/default-plugins/strider/src/main.rs +++ b/default-plugins/strider/src/main.rs @@ -19,7 +19,7 @@ register_worker!( ); impl ZellijPlugin for State { - fn load(&mut self, configuration: BTreeMap) { + fn load(&mut self, _configuration: BTreeMap) { refresh_directory(self); self.search_state.loading = true; subscribe(&[ diff --git a/default-plugins/tab-bar/src/main.rs b/default-plugins/tab-bar/src/main.rs index fc67ef91..20855825 100644 --- a/default-plugins/tab-bar/src/main.rs +++ b/default-plugins/tab-bar/src/main.rs @@ -31,7 +31,7 @@ static ARROW_SEPARATOR: &str = ""; register_plugin!(State); impl ZellijPlugin for State { - fn load(&mut self, configuration: BTreeMap) { + fn load(&mut self, _configuration: BTreeMap) { set_selectable(false); subscribe(&[ EventType::TabUpdate, diff --git a/src/tests/e2e/cases.rs b/src/tests/e2e/cases.rs index b411b4ea..b34138b9 100644 --- a/src/tests/e2e/cases.rs +++ b/src/tests/e2e/cases.rs @@ -808,7 +808,7 @@ pub fn lock_mode() { name: "Send keys that should not be intercepted by the app", instruction: |mut remote_terminal: RemoteTerminal| -> bool { let mut step_is_complete = false; - if remote_terminal.snapshot_contains("<> PANE") { + if remote_terminal.snapshot_contains("INTERFACE LOCKED") { remote_terminal.send_key(&TAB_MODE); remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE); remote_terminal.send_key("abc".as_bytes()); diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap index 209b6779..e6d38062 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__lock_mode.snap @@ -1,6 +1,6 @@ --- source: src/tests/e2e/cases.rs -assertion_line: 840 +assertion_line: 836 expression: last_snapshot --- Zellij (e2e-test)  Tab #1  @@ -26,4 +26,4 @@ expression: last_snapshot │ │ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ Ctrl + LOCK  <> PANE  <> TAB  <> RESIZE  <> MOVE  <> SEARCH  <> SESSION  <> QUIT  - Tip: Alt + => new pane. Alt + <←↓↑→> or Alt + => navigate. Alt + <+|-> => resize pane. + -- INTERFACE LOCKED -- diff --git a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap index fa5d345a..205ff40c 100644 --- a/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap +++ b/src/tests/e2e/snapshots/zellij__tests__e2e__cases__mirrored_sessions-2.snap @@ -26,4 +26,4 @@ expression: second_runner_snapshot │ ││ │ └──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘ Ctrl + LOCK 

PANE  TAB  RESIZE  MOVE  SEARCH  SESSION  QUIT  - New / <←→> Move / Close / Rename / Sync / Break / <[]> Break next/prev / Select + New / <←→> Change focus / Close / Rename / Sync / Toggle / Select pane diff --git a/zellij-server/src/plugins/wasm_bridge.rs b/zellij-server/src/plugins/wasm_bridge.rs index fdc8f389..88039227 100644 --- a/zellij-server/src/plugins/wasm_bridge.rs +++ b/zellij-server/src/plugins/wasm_bridge.rs @@ -447,7 +447,7 @@ impl WasmBridge { // FIXME: This is very janky... Maybe I should write my own macro for Event -> EventType? let event_type = EventType::from_str(&event.to_string()).with_context(err_context)?; - if subs.contains(&event_type) + if (subs.contains(&event_type) || event_type == EventType::PermissionRequestResult) && ((pid.is_none() && cid.is_none()) || (pid.is_none() && cid == Some(*client_id)) || (cid.is_none() && pid == Some(*plugin_id)) @@ -822,10 +822,15 @@ pub fn apply_event_to_plugin( wasi_write_object(&plugin_env.wasi_env, &protobuf_event.encode_to_vec()) .with_context(err_context)?; let update_return = update.call(&[]).with_context(err_context)?; - let should_render = match update_return.get(0) { + let mut should_render = match update_return.get(0) { Some(Value::I32(n)) => *n == 1, _ => false, }; + if let Event::PermissionRequestResult(..) = event { + // we always render in this case, otherwise the request permission screen stays on + // screen + should_render = true; + } if rows > 0 && columns > 0 && should_render { let rendered_bytes = instance .exports diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs index 2ae6770d..1f374f96 100644 --- a/zellij-tile/src/shim.rs +++ b/zellij-tile/src/shim.rs @@ -593,6 +593,7 @@ pub fn switch_session_with_focus( // Utility Functions +#[allow(unused)] /// Returns the `TabInfo` corresponding to the currently active tab fn get_focused_tab(tab_infos: &Vec) -> Option { for tab_info in tab_infos { @@ -603,6 +604,7 @@ fn get_focused_tab(tab_infos: &Vec) -> Option { return None; } +#[allow(unused)] /// Returns the `PaneInfo` corresponding to the currently active pane (ignoring plugins) fn get_focused_pane(tab_position: usize, pane_manifest: &PaneManifest) -> Option { let panes = pane_manifest.panes.get(&tab_position); diff --git a/zellij-utils/assets/plugins/session-manager.wasm b/zellij-utils/assets/plugins/session-manager.wasm index 673af58a..13874da7 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/src/input/actions.rs b/zellij-utils/src/input/actions.rs index 4ed7f029..faeb8a4e 100644 --- a/zellij-utils/src/input/actions.rs +++ b/zellij-utils/src/input/actions.rs @@ -250,6 +250,7 @@ impl Action { pub fn shallow_eq(&self, other_action: &Action) -> bool { match (self, other_action) { (Action::NewTab(..), Action::NewTab(..)) => true, + (Action::LaunchOrFocusPlugin(..), Action::LaunchOrFocusPlugin(..)) => true, _ => self == other_action, } } diff --git a/zellij-utils/src/input/layout.rs b/zellij-utils/src/input/layout.rs index 39d208e8..bd0396a1 100644 --- a/zellij-utils/src/input/layout.rs +++ b/zellij-utils/src/input/layout.rs @@ -207,7 +207,7 @@ impl Run { } } -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash, Default)] pub struct RunPlugin { #[serde(default)] pub _allow_exec_host_cmd: bool, @@ -215,6 +215,16 @@ pub struct RunPlugin { pub configuration: PluginUserConfiguration, } +impl RunPlugin { + pub fn from_url(url: &str) -> Result { + let location = RunPluginLocation::parse(url, None)?; + Ok(RunPlugin { + location, + ..Default::default() + }) + } +} + #[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] pub struct PluginUserConfiguration(BTreeMap); @@ -249,6 +259,12 @@ pub enum RunPluginLocation { Zellij(PluginTag), } +impl Default for RunPluginLocation { + fn default() -> Self { + RunPluginLocation::File(Default::default()) + } +} + impl RunPluginLocation { pub fn parse(location: &str, cwd: Option) -> Result { let url = Url::parse(location)?;