fix(ux): various ui/ux fixes (#2722)
* force plugin render on permission request response
* clear warnings
* Revert "feat(ui): new status bar mode (#2619)"
This reverts commit 27763d26ab.
* adjust status bar help
* fix colors in session manager and shortcut in status-bar
* adjust keybindings
This commit is contained in:
parent
4a1d114753
commit
09d09759b5
20 changed files with 181 additions and 436 deletions
|
|
@ -31,7 +31,7 @@ static ARROW_SEPARATOR: &str = "";
|
||||||
register_plugin!(State);
|
register_plugin!(State);
|
||||||
|
|
||||||
impl ZellijPlugin for State {
|
impl ZellijPlugin for State {
|
||||||
fn load(&mut self, configuration: BTreeMap<String, String>) {
|
fn load(&mut self, _configuration: BTreeMap<String, String>) {
|
||||||
set_selectable(false);
|
set_selectable(false);
|
||||||
subscribe(&[
|
subscribe(&[
|
||||||
EventType::TabUpdate,
|
EventType::TabUpdate,
|
||||||
|
|
|
||||||
|
|
@ -294,7 +294,7 @@ impl LineToRender {
|
||||||
}
|
}
|
||||||
pub fn make_selected(&mut self) {
|
pub fn make_selected(&mut self) {
|
||||||
self.is_selected = true;
|
self.is_selected = true;
|
||||||
match self.colors.palette.gray {
|
match self.colors.palette.bg {
|
||||||
PaletteColor::EightBit(byte) => {
|
PaletteColor::EightBit(byte) => {
|
||||||
self.line = format!(
|
self.line = format!(
|
||||||
"\u{1b}[48;5;{byte}m\u{1b}[K\r\u{1b}[48;5;{byte}m{}",
|
"\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)) => {
|
PaletteColor::Rgb((r, g, b)) => {
|
||||||
self.line = format!(
|
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
|
r, g, b, r, g, b, self.line
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,13 @@ use crate::{
|
||||||
};
|
};
|
||||||
use crate::{ColoredElements, LinePart};
|
use crate::{ColoredElements, LinePart};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
struct KeyShortcut {
|
struct KeyShortcut {
|
||||||
mode: KeyMode,
|
mode: KeyMode,
|
||||||
pub action: KeyAction,
|
action: KeyAction,
|
||||||
key: Option<Key>,
|
key: Option<Key>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum KeyAction {
|
enum KeyAction {
|
||||||
Lock,
|
Lock,
|
||||||
Pane,
|
Pane,
|
||||||
|
|
@ -28,7 +27,6 @@ enum KeyAction {
|
||||||
Tmux,
|
Tmux,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
enum KeyMode {
|
enum KeyMode {
|
||||||
Unselected,
|
Unselected,
|
||||||
UnselectedAlternate,
|
UnselectedAlternate,
|
||||||
|
|
@ -36,20 +34,6 @@ enum KeyMode {
|
||||||
Disabled,
|
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 {
|
impl KeyShortcut {
|
||||||
pub fn new(mode: KeyMode, action: KeyAction, key: Option<Key>) -> Self {
|
pub fn new(mode: KeyMode, action: KeyAction, key: Option<Key>) -> Self {
|
||||||
KeyShortcut { mode, action, key }
|
KeyShortcut { mode, action, key }
|
||||||
|
|
@ -73,7 +57,17 @@ impl KeyShortcut {
|
||||||
Some(k) => k,
|
Some(k) => k,
|
||||||
None => return String::from("?"),
|
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(
|
fn key_indicators(
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
keys: &[KeyShortcut],
|
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<Key>) -> Option<Key> {
|
pub fn to_char(kv: Vec<Key>) -> Option<Key> {
|
||||||
let key = kv
|
let key = kv
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -582,19 +419,6 @@ pub fn to_char(kv: Vec<Key>) -> Option<Key> {
|
||||||
key.cloned()
|
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`].
|
/// Get the [`KeyShortcut`] for a specific [`InputMode`].
|
||||||
///
|
///
|
||||||
/// Iterates over the contents of `shortcuts` to find the [`KeyShortcut`] with the [`KeyAction`]
|
/// 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
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn first_line_supermode(
|
pub fn first_line(
|
||||||
standby_mode: &InputMode,
|
|
||||||
help: &ModeInfo,
|
help: &ModeInfo,
|
||||||
tab_info: Option<&TabInfo>,
|
tab_info: Option<&TabInfo>,
|
||||||
max_len: usize,
|
max_len: usize,
|
||||||
|
|
@ -634,129 +457,9 @@ pub fn first_line_supermode(
|
||||||
) -> LinePart {
|
) -> LinePart {
|
||||||
let supports_arrow_fonts = !help.capabilities.arrow_fonts;
|
let supports_arrow_fonts = !help.capabilities.arrow_fonts;
|
||||||
let colored_elements = color_elements(help.style.colors, !supports_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<KeyShortcut> =
|
|
||||||
default_keys.iter().cloned().take(position).collect();
|
|
||||||
let second_keybinds: Vec<KeyShortcut> =
|
|
||||||
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<KeyShortcut> {
|
|
||||||
let binds = &help.get_mode_keybinds();
|
let binds = &help.get_mode_keybinds();
|
||||||
vec![
|
// Unselect all by default
|
||||||
|
let mut default_keys = vec![
|
||||||
KeyShortcut::new(
|
KeyShortcut::new(
|
||||||
KeyMode::Unselected,
|
KeyMode::Unselected,
|
||||||
KeyAction::Lock,
|
KeyAction::Lock,
|
||||||
|
|
@ -809,20 +512,7 @@ fn generate_default_keys(help: &ModeInfo) -> Vec<KeyShortcut> {
|
||||||
KeyAction::Quit,
|
KeyAction::Quit,
|
||||||
to_char(action_key(binds, &[Action::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) {
|
if let Some(key_shortcut) = get_key_shortcut_for_mode(&mut default_keys, &help.mode) {
|
||||||
key_shortcut.mode = KeyMode::Selected;
|
key_shortcut.mode = KeyMode::Selected;
|
||||||
|
|
@ -849,14 +539,25 @@ pub fn first_line(
|
||||||
key_indicators(max_len, &default_keys, colored_elements, separator, help);
|
key_indicators(max_len, &default_keys, colored_elements, separator, help);
|
||||||
if key_indicators.len < max_len {
|
if key_indicators.len < max_len {
|
||||||
if let Some(tab_info) = tab_info {
|
if let Some(tab_info) = tab_info {
|
||||||
let remaining_space = max_len - key_indicators.len;
|
let mut remaining_space = max_len - key_indicators.len;
|
||||||
key_indicators.append(&swap_layout_status_and_padding(
|
if let Some(swap_layout_status) = swap_layout_status(
|
||||||
&tab_info,
|
|
||||||
remaining_space,
|
remaining_space,
|
||||||
separator,
|
&tab_info.active_swap_layout_name,
|
||||||
colored_elements,
|
tab_info.is_swap_layout_dirty,
|
||||||
help,
|
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
|
key_indicators
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,10 @@ use zellij_tile::prelude::actions::Action;
|
||||||
use zellij_tile::prelude::*;
|
use zellij_tile::prelude::*;
|
||||||
use zellij_tile_utils::{palette_match, style};
|
use zellij_tile_utils::{palette_match, style};
|
||||||
|
|
||||||
use first_line::{first_line, first_line_supermode};
|
use first_line::first_line;
|
||||||
use second_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,
|
text_copied_hint,
|
||||||
};
|
};
|
||||||
use tip::utils::get_cached_tip_name;
|
use tip::utils::get_cached_tip_name;
|
||||||
|
|
@ -34,10 +35,6 @@ struct State {
|
||||||
mode_info: ModeInfo,
|
mode_info: ModeInfo,
|
||||||
text_copy_destination: Option<CopyDestination>,
|
text_copy_destination: Option<CopyDestination>,
|
||||||
display_system_clipboard_failure: bool,
|
display_system_clipboard_failure: bool,
|
||||||
|
|
||||||
supermode: bool,
|
|
||||||
standby_mode: InputMode,
|
|
||||||
current_mode: InputMode,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
register_plugin!(State);
|
register_plugin!(State);
|
||||||
|
|
@ -64,7 +61,6 @@ impl Display for LinePart {
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct ColoredElements {
|
pub struct ColoredElements {
|
||||||
pub selected: SegmentStyle,
|
pub selected: SegmentStyle,
|
||||||
pub selected_standby_shortcut: SegmentStyle,
|
|
||||||
pub unselected: SegmentStyle,
|
pub unselected: SegmentStyle,
|
||||||
pub unselected_alternate: SegmentStyle,
|
pub unselected_alternate: SegmentStyle,
|
||||||
pub disabled: 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(),
|
styled_text: style!(background, palette.green).bold(),
|
||||||
suffix_separator: style!(palette.green, background).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 {
|
unselected: SegmentStyle {
|
||||||
prefix_separator: style!(background, palette.fg),
|
prefix_separator: style!(background, palette.fg),
|
||||||
char_left_separator: style!(background, palette.fg).bold(),
|
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(),
|
styled_text: style!(background, palette.green).bold(),
|
||||||
suffix_separator: style!(palette.green, background).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 {
|
unselected: SegmentStyle {
|
||||||
prefix_separator: style!(background, palette.fg),
|
prefix_separator: style!(background, palette.fg),
|
||||||
char_left_separator: style!(background, palette.fg).bold(),
|
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 {
|
impl ZellijPlugin for State {
|
||||||
fn load(&mut self, configuration: BTreeMap<String, String>) {
|
fn load(&mut self, _configuration: BTreeMap<String, String>) {
|
||||||
// TODO: Should be able to choose whether to use the cache through config.
|
// TODO: Should be able to choose whether to use the cache through config.
|
||||||
self.tip_name = get_cached_tip_name();
|
self.tip_name = get_cached_tip_name();
|
||||||
set_selectable(false);
|
set_selectable(false);
|
||||||
|
|
@ -208,47 +188,12 @@ impl ZellijPlugin for State {
|
||||||
EventType::InputReceived,
|
EventType::InputReceived,
|
||||||
EventType::SystemClipboardFailure,
|
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 {
|
fn update(&mut self, event: Event) -> bool {
|
||||||
let mut should_render = false;
|
let mut should_render = false;
|
||||||
match event {
|
match event {
|
||||||
Event::ModeUpdate(mode_info) => {
|
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 {
|
if self.mode_info != mode_info {
|
||||||
should_render = true;
|
should_render = true;
|
||||||
}
|
}
|
||||||
|
|
@ -300,17 +245,7 @@ impl ZellijPlugin for State {
|
||||||
};
|
};
|
||||||
|
|
||||||
let active_tab = self.tabs.iter().find(|t| t.active);
|
let active_tab = self.tabs.iter().find(|t| t.active);
|
||||||
let first_line = if self.supermode {
|
let first_line = first_line(&self.mode_info, active_tab, cols, separator);
|
||||||
first_line_supermode(
|
|
||||||
&self.standby_mode,
|
|
||||||
&self.mode_info,
|
|
||||||
active_tab,
|
|
||||||
cols,
|
|
||||||
separator,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
first_line(&self.mode_info, active_tab, cols, separator)
|
|
||||||
};
|
|
||||||
let second_line = self.second_line(cols);
|
let second_line = self.second_line(cols);
|
||||||
|
|
||||||
let background = match self.mode_info.style.colors.theme_hue {
|
let background = match self.mode_info.style.colors.theme_hue {
|
||||||
|
|
@ -362,7 +297,11 @@ impl State {
|
||||||
} else if let Some(active_tab) = active_tab {
|
} else if let Some(active_tab) = active_tab {
|
||||||
if active_tab.is_fullscreen_active {
|
if active_tab.is_fullscreen_active {
|
||||||
match self.mode_info.mode {
|
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,
|
&self.mode_info.style.colors,
|
||||||
active_tab.panes_to_hide,
|
active_tab.panes_to_hide,
|
||||||
),
|
),
|
||||||
|
|
@ -370,8 +309,9 @@ impl State {
|
||||||
}
|
}
|
||||||
} else if active_tab.are_floating_panes_visible {
|
} else if active_tab.are_floating_panes_visible {
|
||||||
match self.mode_info.mode {
|
match self.mode_info.mode {
|
||||||
InputMode::Normal | InputMode::Locked => {
|
InputMode::Normal => floating_panes_are_visible(&self.mode_info),
|
||||||
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),
|
_ => keybinds(&self.mode_info, &self.tip_name, cols),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<Key>) -> LinePart {
|
fn add_shortcut(help: &ModeInfo, linepart: &LinePart, text: &str, keys: Vec<Key>) -> LinePart {
|
||||||
let shortcut = if linepart.len == 0 {
|
let shortcut = if linepart.len == 0 {
|
||||||
full_length_shortcut(true, keys, text, help.style.colors)
|
full_length_shortcut(true, keys, text, help.style.colors)
|
||||||
|
|
@ -166,12 +180,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
|
||||||
(s("Rename"), s("Rename"),
|
(s("Rename"), s("Rename"),
|
||||||
action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])),
|
action_key(&km, &[A::SwitchToMode(IM::RenameTab), A::TabNameInput(vec![0])])),
|
||||||
(s("Sync"), s("Sync"), action_key(&km, &[A::ToggleActiveSyncTab, TO_NORMAL])),
|
(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("Toggle"), s("Toggle"), action_key(&km, &[A::ToggleTab])),
|
||||||
(s("Break pane to next/prev tab"), s("Break next/prev"),
|
|
||||||
action_key_group(&km, &[
|
|
||||||
&[A::BreakPaneLeft, TO_NORMAL],
|
|
||||||
&[A::BreakPaneRight, TO_NORMAL]
|
|
||||||
])),
|
|
||||||
(s("Select pane"), s("Select"), to_normal_key),
|
(s("Select pane"), s("Select"), to_normal_key),
|
||||||
]} else if mi.mode == IM::Resize { vec![
|
]} else if mi.mode == IM::Resize { vec![
|
||||||
(s("Increase/Decrease size"), s("Increase/Decrease"),
|
(s("Increase/Decrease size"), s("Increase/Decrease"),
|
||||||
|
|
@ -231,6 +240,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
|
||||||
action_key(&km, &[A::SearchToggleOption(SOpt::WholeWord)])),
|
action_key(&km, &[A::SearchToggleOption(SOpt::WholeWord)])),
|
||||||
]} else if mi.mode == IM::Session { vec![
|
]} else if mi.mode == IM::Session { vec![
|
||||||
(s("Detach"), s("Detach"), action_key(&km, &[Action::Detach])),
|
(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),
|
(s("Select pane"), s("Select"), to_normal_key),
|
||||||
]} else if mi.mode == IM::Tmux { vec![
|
]} else if mi.mode == IM::Tmux { vec![
|
||||||
(s("Move focus"), s("Move"), action_key_group(&km, &[
|
(s("Move focus"), s("Move"), action_key_group(&km, &[
|
||||||
|
|
@ -255,7 +265,8 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<Key>)> {
|
||||||
|
|
||||||
fn full_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart {
|
fn full_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart {
|
||||||
match help.mode {
|
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),
|
_ => 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 {
|
fn shortened_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart {
|
||||||
match help.mode {
|
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),
|
_ => 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 {
|
fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> LinePart {
|
||||||
match help.mode {
|
match help.mode {
|
||||||
InputMode::Normal | InputMode::Locked => {
|
InputMode::Normal => {
|
||||||
let line_part = tip(help);
|
let line_part = tip(help);
|
||||||
if line_part.len <= max_len {
|
if line_part.len <= max_len {
|
||||||
line_part
|
line_part
|
||||||
|
|
@ -303,6 +315,14 @@ fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> Lin
|
||||||
LinePart::default()
|
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),
|
_ => 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)]
|
#[cfg(test)]
|
||||||
/// Unit tests.
|
/// Unit tests.
|
||||||
///
|
///
|
||||||
|
|
@ -581,6 +663,7 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(ret, " / Ctrl + <a|b|c> Foobar");
|
assert_eq!(ret, " / Ctrl + <a|b|c> Foobar");
|
||||||
}
|
}
|
||||||
|
//pub fn keybinds(help: &ModeInfo, tip_name: &str, max_width: usize) -> LinePart {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// Note how it leaves out elements that don't exist!
|
// 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 = keybinds(&mode_info, "quicknav", 500);
|
||||||
let ret = unstyle(ret);
|
let ret = unstyle(ret);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(ret, " <BACKSPACE> New / Ctrl + <a|ENTER|1|SPACE> Change Focus / <ESC> Close / <END> Toggle Fullscreen");
|
||||||
ret,
|
|
||||||
" <BACKSPACE> New / Ctrl + <a|ENTER|1|SPACE> Change Focus / <ESC> Close / <END> Toggle Fullscreen"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ pub fn compact_layout_short(help: &ModeInfo) -> LinePart {
|
||||||
|
|
||||||
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
||||||
let to_pane = action_key(
|
let to_pane = action_key(
|
||||||
&help.get_keybinds_for_mode(InputMode::Normal),
|
&help.get_mode_keybinds(),
|
||||||
&[Action::SwitchToMode(InputMode::Pane)],
|
&[Action::SwitchToMode(InputMode::Pane)],
|
||||||
);
|
);
|
||||||
let pane_frames = action_key(
|
let pane_frames = action_key(
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ pub fn edit_scrollbuffer_short(help: &ModeInfo) -> LinePart {
|
||||||
|
|
||||||
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
||||||
let to_pane = action_key(
|
let to_pane = action_key(
|
||||||
&help.get_keybinds_for_mode(InputMode::Normal),
|
&help.get_mode_keybinds(),
|
||||||
&[Action::SwitchToMode(InputMode::Scroll)],
|
&[Action::SwitchToMode(InputMode::Scroll)],
|
||||||
);
|
);
|
||||||
let edit_buffer = action_key(
|
let edit_buffer = action_key(
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ pub fn floating_panes_mouse_short(help: &ModeInfo) -> LinePart {
|
||||||
|
|
||||||
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
||||||
let to_pane = action_key(
|
let to_pane = action_key(
|
||||||
&help.get_keybinds_for_mode(InputMode::Normal),
|
&help.get_mode_keybinds(),
|
||||||
&[Action::SwitchToMode(InputMode::Pane)],
|
&[Action::SwitchToMode(InputMode::Pane)],
|
||||||
);
|
);
|
||||||
let floating_toggle = action_key(
|
let floating_toggle = action_key(
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ struct Keygroups<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_keybinds(help: &ModeInfo) -> Keygroups {
|
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_keys = action_key(&normal_keymap, &[Action::NewPane(None, None)]);
|
||||||
let new_pane = if new_pane_keys.is_empty() {
|
let new_pane = if new_pane_keys.is_empty() {
|
||||||
vec![Style::new().bold().paint("UNBOUND")]
|
vec![Style::new().bold().paint("UNBOUND")]
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ pub fn sync_tab_short(help: &ModeInfo) -> LinePart {
|
||||||
|
|
||||||
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
fn add_keybinds(help: &ModeInfo) -> Vec<ANSIString> {
|
||||||
let to_tab = action_key(
|
let to_tab = action_key(
|
||||||
&help.get_keybinds_for_mode(InputMode::Normal),
|
&help.get_mode_keybinds(),
|
||||||
&[Action::SwitchToMode(InputMode::Tab)],
|
&[Action::SwitchToMode(InputMode::Tab)],
|
||||||
);
|
);
|
||||||
let sync_tabs = action_key(
|
let sync_tabs = action_key(
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ register_worker!(
|
||||||
);
|
);
|
||||||
|
|
||||||
impl ZellijPlugin for State {
|
impl ZellijPlugin for State {
|
||||||
fn load(&mut self, configuration: BTreeMap<String, String>) {
|
fn load(&mut self, _configuration: BTreeMap<String, String>) {
|
||||||
refresh_directory(self);
|
refresh_directory(self);
|
||||||
self.search_state.loading = true;
|
self.search_state.loading = true;
|
||||||
subscribe(&[
|
subscribe(&[
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ static ARROW_SEPARATOR: &str = "";
|
||||||
register_plugin!(State);
|
register_plugin!(State);
|
||||||
|
|
||||||
impl ZellijPlugin for State {
|
impl ZellijPlugin for State {
|
||||||
fn load(&mut self, configuration: BTreeMap<String, String>) {
|
fn load(&mut self, _configuration: BTreeMap<String, String>) {
|
||||||
set_selectable(false);
|
set_selectable(false);
|
||||||
subscribe(&[
|
subscribe(&[
|
||||||
EventType::TabUpdate,
|
EventType::TabUpdate,
|
||||||
|
|
|
||||||
|
|
@ -808,7 +808,7 @@ pub fn lock_mode() {
|
||||||
name: "Send keys that should not be intercepted by the app",
|
name: "Send keys that should not be intercepted by the app",
|
||||||
instruction: |mut remote_terminal: RemoteTerminal| -> bool {
|
instruction: |mut remote_terminal: RemoteTerminal| -> bool {
|
||||||
let mut step_is_complete = false;
|
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(&TAB_MODE);
|
||||||
remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE);
|
remote_terminal.send_key(&NEW_TAB_IN_TAB_MODE);
|
||||||
remote_terminal.send_key("abc".as_bytes());
|
remote_terminal.send_key("abc".as_bytes());
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: src/tests/e2e/cases.rs
|
source: src/tests/e2e/cases.rs
|
||||||
assertion_line: 840
|
assertion_line: 836
|
||||||
expression: last_snapshot
|
expression: last_snapshot
|
||||||
---
|
---
|
||||||
Zellij (e2e-test) Tab #1
|
Zellij (e2e-test) Tab #1
|
||||||
|
|
@ -26,4 +26,4 @@ expression: last_snapshot
|
||||||
│ │
|
│ │
|
||||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||||
Ctrl + <g> LOCK <> PANE <> TAB <> RESIZE <> MOVE <> SEARCH <> SESSION <> QUIT
|
Ctrl + <g> LOCK <> PANE <> TAB <> RESIZE <> MOVE <> SEARCH <> SESSION <> QUIT
|
||||||
Tip: Alt + <n> => new pane. Alt + <←↓↑→> or Alt + <hjkl> => navigate. Alt + <+|-> => resize pane.
|
-- INTERFACE LOCKED --
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,4 @@ expression: second_runner_snapshot
|
||||||
│ ││ │
|
│ ││ │
|
||||||
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────────────┘└──────────────────────────────────────────────────────────┘
|
||||||
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
Ctrl + <g> LOCK <p> PANE <t> TAB <n> RESIZE <h> MOVE <s> SEARCH <o> SESSION <q> QUIT
|
||||||
<n> New / <←→> Move / <x> Close / <r> Rename / <s> Sync / <b> Break / <[]> Break next/prev / <ENTER> Select
|
<n> New / <←→> Change focus / <x> Close / <r> Rename / <s> Sync / <TAB> Toggle / <ENTER> Select pane
|
||||||
|
|
|
||||||
|
|
@ -447,7 +447,7 @@ impl WasmBridge {
|
||||||
// FIXME: This is very janky... Maybe I should write my own macro for Event -> EventType?
|
// FIXME: This is very janky... Maybe I should write my own macro for Event -> EventType?
|
||||||
let event_type =
|
let event_type =
|
||||||
EventType::from_str(&event.to_string()).with_context(err_context)?;
|
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.is_none())
|
||||||
|| (pid.is_none() && cid == Some(*client_id))
|
|| (pid.is_none() && cid == Some(*client_id))
|
||||||
|| (cid.is_none() && pid == Some(*plugin_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())
|
wasi_write_object(&plugin_env.wasi_env, &protobuf_event.encode_to_vec())
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
let update_return = update.call(&[]).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,
|
Some(Value::I32(n)) => *n == 1,
|
||||||
_ => false,
|
_ => 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 {
|
if rows > 0 && columns > 0 && should_render {
|
||||||
let rendered_bytes = instance
|
let rendered_bytes = instance
|
||||||
.exports
|
.exports
|
||||||
|
|
|
||||||
|
|
@ -593,6 +593,7 @@ pub fn switch_session_with_focus(
|
||||||
|
|
||||||
// Utility Functions
|
// Utility Functions
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
/// Returns the `TabInfo` corresponding to the currently active tab
|
/// Returns the `TabInfo` corresponding to the currently active tab
|
||||||
fn get_focused_tab(tab_infos: &Vec<TabInfo>) -> Option<TabInfo> {
|
fn get_focused_tab(tab_infos: &Vec<TabInfo>) -> Option<TabInfo> {
|
||||||
for tab_info in tab_infos {
|
for tab_info in tab_infos {
|
||||||
|
|
@ -603,6 +604,7 @@ fn get_focused_tab(tab_infos: &Vec<TabInfo>) -> Option<TabInfo> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
/// Returns the `PaneInfo` corresponding to the currently active pane (ignoring plugins)
|
/// Returns the `PaneInfo` corresponding to the currently active pane (ignoring plugins)
|
||||||
fn get_focused_pane(tab_position: usize, pane_manifest: &PaneManifest) -> Option<PaneInfo> {
|
fn get_focused_pane(tab_position: usize, pane_manifest: &PaneManifest) -> Option<PaneInfo> {
|
||||||
let panes = pane_manifest.panes.get(&tab_position);
|
let panes = pane_manifest.panes.get(&tab_position);
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -250,6 +250,7 @@ impl Action {
|
||||||
pub fn shallow_eq(&self, other_action: &Action) -> bool {
|
pub fn shallow_eq(&self, other_action: &Action) -> bool {
|
||||||
match (self, other_action) {
|
match (self, other_action) {
|
||||||
(Action::NewTab(..), Action::NewTab(..)) => true,
|
(Action::NewTab(..), Action::NewTab(..)) => true,
|
||||||
|
(Action::LaunchOrFocusPlugin(..), Action::LaunchOrFocusPlugin(..)) => true,
|
||||||
_ => self == other_action,
|
_ => self == other_action,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
pub struct RunPlugin {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub _allow_exec_host_cmd: bool,
|
pub _allow_exec_host_cmd: bool,
|
||||||
|
|
@ -215,6 +215,16 @@ pub struct RunPlugin {
|
||||||
pub configuration: PluginUserConfiguration,
|
pub configuration: PluginUserConfiguration,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RunPlugin {
|
||||||
|
pub fn from_url(url: &str) -> Result<Self, PluginsConfigError> {
|
||||||
|
let location = RunPluginLocation::parse(url, None)?;
|
||||||
|
Ok(RunPlugin {
|
||||||
|
location,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||||
pub struct PluginUserConfiguration(BTreeMap<String, String>);
|
pub struct PluginUserConfiguration(BTreeMap<String, String>);
|
||||||
|
|
||||||
|
|
@ -249,6 +259,12 @@ pub enum RunPluginLocation {
|
||||||
Zellij(PluginTag),
|
Zellij(PluginTag),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for RunPluginLocation {
|
||||||
|
fn default() -> Self {
|
||||||
|
RunPluginLocation::File(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RunPluginLocation {
|
impl RunPluginLocation {
|
||||||
pub fn parse(location: &str, cwd: Option<PathBuf>) -> Result<Self, PluginsConfigError> {
|
pub fn parse(location: &str, cwd: Option<PathBuf>) -> Result<Self, PluginsConfigError> {
|
||||||
let url = Url::parse(location)?;
|
let url = Url::parse(location)?;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue