* rebind action working * functional ui * responsive ui * some refactoring * properly reset ui state * minor fixes * style(fmt): rustfmt * style(fmt): remove dead code
1262 lines
48 KiB
Rust
1262 lines
48 KiB
Rust
use std::collections::BTreeSet;
|
|
use zellij_tile::prelude::*;
|
|
|
|
use crate::ui_components::{back_to_presets, info_line};
|
|
|
|
use crate::{POSSIBLE_MODIFIERS, WIDTH_BREAKPOINTS};
|
|
|
|
#[derive(Debug)]
|
|
pub struct RebindLeadersScreen {
|
|
selected_primary_key_index: usize,
|
|
selected_secondary_key_index: usize,
|
|
main_leader_selected: bool,
|
|
rebinding_main_leader: bool,
|
|
browsing_primary_modifier: bool,
|
|
browsing_secondary_modifier: bool,
|
|
main_leader: Option<KeyWithModifier>,
|
|
primary_modifier: BTreeSet<KeyModifier>,
|
|
secondary_modifier: BTreeSet<KeyModifier>,
|
|
latest_mode_info: Option<ModeInfo>,
|
|
notification: Option<String>,
|
|
is_rebinding_for_presets: bool,
|
|
ui_is_dirty: bool,
|
|
}
|
|
|
|
impl Default for RebindLeadersScreen {
|
|
fn default() -> Self {
|
|
let mut primary_modifier = BTreeSet::new();
|
|
primary_modifier.insert(KeyModifier::Ctrl);
|
|
let mut secondary_modifier = BTreeSet::new();
|
|
secondary_modifier.insert(KeyModifier::Alt);
|
|
RebindLeadersScreen {
|
|
selected_primary_key_index: 0,
|
|
selected_secondary_key_index: 0,
|
|
main_leader_selected: false,
|
|
rebinding_main_leader: false,
|
|
browsing_primary_modifier: false,
|
|
browsing_secondary_modifier: false,
|
|
main_leader: None,
|
|
primary_modifier,
|
|
secondary_modifier,
|
|
latest_mode_info: None,
|
|
notification: None,
|
|
is_rebinding_for_presets: false,
|
|
ui_is_dirty: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl RebindLeadersScreen {
|
|
pub fn with_rebinding_for_presets(mut self) -> Self {
|
|
self.is_rebinding_for_presets = true;
|
|
self
|
|
}
|
|
pub fn with_mode_info(mut self, latest_mode_info: Option<ModeInfo>) -> Self {
|
|
self.latest_mode_info = latest_mode_info;
|
|
self.hard_reset_ui_state();
|
|
self
|
|
}
|
|
pub fn update_mode_info(&mut self, mode_info: ModeInfo) {
|
|
self.latest_mode_info = Some(mode_info);
|
|
if !self.ui_is_dirty {
|
|
self.set_main_leader_from_keybindings();
|
|
self.set_primary_and_secondary_modifiers_from_keybindings();
|
|
}
|
|
}
|
|
pub fn primary_and_secondary_modifiers(
|
|
&self,
|
|
) -> (BTreeSet<KeyModifier>, BTreeSet<KeyModifier>) {
|
|
(
|
|
self.primary_modifier.clone(),
|
|
self.secondary_modifier.clone(),
|
|
)
|
|
}
|
|
fn set_main_leader_from_keybindings(&mut self) {
|
|
self.main_leader = self.latest_mode_info.as_ref().and_then(|mode_info| {
|
|
mode_info
|
|
.keybinds
|
|
.iter()
|
|
.find_map(|m| {
|
|
if m.0 == InputMode::Locked {
|
|
Some(m.1.clone())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.and_then(|k| {
|
|
k.into_iter().find_map(|(k, a)| {
|
|
if a == &[actions::Action::SwitchToMode(InputMode::Normal)] {
|
|
Some(k)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
})
|
|
});
|
|
}
|
|
fn set_primary_and_secondary_modifiers_from_keybindings(&mut self) {
|
|
let mut primary_modifier = self.latest_mode_info.as_ref().and_then(|mode_info| {
|
|
mode_info
|
|
.keybinds
|
|
.iter()
|
|
.find_map(|m| {
|
|
if m.0 == InputMode::Locked {
|
|
Some(m.1.clone())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.and_then(|k| {
|
|
k.into_iter().find_map(|(k, a)| {
|
|
if a == &[actions::Action::SwitchToMode(InputMode::Normal)] {
|
|
Some(k.key_modifiers.clone())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
})
|
|
});
|
|
let mut secondary_modifier = self.latest_mode_info.as_ref().and_then(|mode_info| {
|
|
let base_mode = mode_info.base_mode.unwrap_or(InputMode::Normal);
|
|
mode_info
|
|
.keybinds
|
|
.iter()
|
|
.find_map(|m| {
|
|
if m.0 == base_mode {
|
|
Some(m.1.clone())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.and_then(|k| {
|
|
k.into_iter().find_map(|(k, a)| {
|
|
if a == &[actions::Action::NewPane(None, None, false)] {
|
|
Some(k.key_modifiers.clone())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
})
|
|
});
|
|
if let Some(primary_modifier) = primary_modifier.take() {
|
|
self.primary_modifier = primary_modifier;
|
|
}
|
|
if let Some(secondary_modifier) = secondary_modifier.take() {
|
|
self.secondary_modifier = secondary_modifier;
|
|
}
|
|
}
|
|
pub fn set_unlock_toggle_selected(&mut self) {
|
|
self.main_leader_selected = true;
|
|
self.selected_primary_key_index = 0;
|
|
self.selected_secondary_key_index = 0;
|
|
self.rebinding_main_leader = false;
|
|
self.browsing_primary_modifier = false;
|
|
self.browsing_secondary_modifier = false;
|
|
}
|
|
pub fn set_primary_modifier_selected(&mut self) {
|
|
self.browsing_primary_modifier = true;
|
|
self.main_leader_selected = false;
|
|
self.selected_primary_key_index = 0;
|
|
self.selected_secondary_key_index = 0;
|
|
self.rebinding_main_leader = false;
|
|
self.browsing_secondary_modifier = false;
|
|
}
|
|
pub fn set_secondary_modifier_selected(&mut self) {
|
|
self.browsing_secondary_modifier = true;
|
|
self.browsing_primary_modifier = false;
|
|
self.main_leader_selected = false;
|
|
self.selected_primary_key_index = 0;
|
|
self.selected_secondary_key_index = 0;
|
|
self.rebinding_main_leader = false;
|
|
}
|
|
pub fn set_rebinding_unlock_toggle(&mut self) {
|
|
self.rebinding_main_leader = true;
|
|
self.browsing_secondary_modifier = false;
|
|
self.browsing_primary_modifier = false;
|
|
self.main_leader_selected = false;
|
|
self.selected_primary_key_index = 0;
|
|
self.selected_secondary_key_index = 0;
|
|
}
|
|
pub fn move_secondary_index_down(&mut self) {
|
|
if self.selected_secondary_key_index < POSSIBLE_MODIFIERS.len().saturating_sub(1) {
|
|
self.selected_secondary_key_index += 1;
|
|
} else {
|
|
self.set_unlock_toggle_selected();
|
|
}
|
|
}
|
|
pub fn move_secondary_index_up(&mut self) {
|
|
if self.selected_secondary_key_index > 0 {
|
|
self.selected_secondary_key_index -= 1;
|
|
} else {
|
|
self.set_unlock_toggle_selected();
|
|
}
|
|
}
|
|
pub fn move_selection_for_default_preset(&mut self, key: &KeyWithModifier) {
|
|
if self.browsing_primary_modifier {
|
|
if key.bare_key == BareKey::Left && key.has_no_modifiers() {
|
|
self.browsing_primary_modifier = false;
|
|
self.browsing_secondary_modifier = true;
|
|
self.selected_secondary_key_index = self.selected_primary_key_index;
|
|
} else if key.bare_key == BareKey::Right && key.has_no_modifiers() {
|
|
self.browsing_primary_modifier = false;
|
|
self.browsing_secondary_modifier = true;
|
|
self.selected_secondary_key_index = self.selected_primary_key_index;
|
|
} else if key.bare_key == BareKey::Down && key.has_no_modifiers() {
|
|
if self.selected_primary_key_index < POSSIBLE_MODIFIERS.len().saturating_sub(1) {
|
|
self.selected_primary_key_index += 1;
|
|
}
|
|
} else if key.bare_key == BareKey::Up && key.has_no_modifiers() {
|
|
if self.selected_primary_key_index > 0 {
|
|
self.selected_primary_key_index -= 1;
|
|
}
|
|
}
|
|
} else if self.browsing_secondary_modifier {
|
|
if key.bare_key == BareKey::Left && key.has_no_modifiers() {
|
|
self.browsing_secondary_modifier = false;
|
|
self.browsing_primary_modifier = true;
|
|
self.selected_primary_key_index = self.selected_secondary_key_index;
|
|
} else if key.bare_key == BareKey::Right && key.has_no_modifiers() {
|
|
self.browsing_secondary_modifier = false;
|
|
self.browsing_primary_modifier = true;
|
|
self.selected_primary_key_index = self.selected_secondary_key_index;
|
|
} else if key.bare_key == BareKey::Down && key.has_no_modifiers() {
|
|
if self.selected_secondary_key_index < POSSIBLE_MODIFIERS.len().saturating_sub(1) {
|
|
self.selected_secondary_key_index += 1;
|
|
}
|
|
} else if key.bare_key == BareKey::Up && key.has_no_modifiers() {
|
|
if self.selected_secondary_key_index > 0 {
|
|
self.selected_secondary_key_index -= 1;
|
|
}
|
|
}
|
|
} else {
|
|
self.set_primary_modifier_selected();
|
|
}
|
|
}
|
|
pub fn move_selection_for_unlock_first(&mut self, key: &KeyWithModifier) {
|
|
if self.browsing_secondary_modifier {
|
|
if (key.bare_key == BareKey::Left || key.bare_key == BareKey::Right)
|
|
&& key.has_no_modifiers()
|
|
{
|
|
self.set_unlock_toggle_selected();
|
|
} else if key.bare_key == BareKey::Down && key.has_no_modifiers() {
|
|
self.move_secondary_index_down();
|
|
} else if key.bare_key == BareKey::Up && key.has_no_modifiers() {
|
|
self.move_secondary_index_up();
|
|
}
|
|
} else if self.main_leader_selected {
|
|
if (key.bare_key == BareKey::Down
|
|
|| key.bare_key == BareKey::Up
|
|
|| key.bare_key == BareKey::Right
|
|
|| key.bare_key == BareKey::Left)
|
|
&& key.has_no_modifiers()
|
|
{
|
|
self.set_secondary_modifier_selected();
|
|
}
|
|
} else {
|
|
self.set_unlock_toggle_selected();
|
|
}
|
|
}
|
|
pub fn render(
|
|
&mut self,
|
|
rows: usize,
|
|
cols: usize,
|
|
ui_size: usize,
|
|
notification: &Option<String>,
|
|
) {
|
|
if self.is_rebinding_for_presets {
|
|
back_to_presets();
|
|
}
|
|
let notification = notification.clone().or_else(|| self.notification.clone());
|
|
if self.currently_in_unlock_first() {
|
|
self.render_unlock_first(rows, cols);
|
|
} else {
|
|
self.render_default_preset(rows, cols);
|
|
}
|
|
let warning_text = self.warning_text(cols);
|
|
info_line(rows, cols, ui_size, ¬ification, &warning_text, None);
|
|
}
|
|
fn render_unlock_first(&mut self, rows: usize, cols: usize) {
|
|
self.render_screen_title_unlock_first(rows, cols);
|
|
self.render_unlock_toggle(rows, cols);
|
|
self.render_secondary_modifier_selector(rows, cols);
|
|
self.render_help_text(rows, cols);
|
|
}
|
|
fn render_default_preset(&mut self, rows: usize, cols: usize) {
|
|
self.render_screen_title_default_preset(rows, cols);
|
|
self.render_primary_modifier_selector(rows, cols);
|
|
self.render_secondary_modifier_selector(rows, cols);
|
|
self.render_help_text(rows, cols);
|
|
}
|
|
fn render_primary_modifier_selector(&self, rows: usize, cols: usize) {
|
|
let screen_width = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
WIDTH_BREAKPOINTS.0
|
|
} else {
|
|
WIDTH_BREAKPOINTS.1
|
|
};
|
|
let base_x = cols.saturating_sub(screen_width) / 2;
|
|
let base_y = rows.saturating_sub(7) / 2;
|
|
let primary_modifier_key_text = self.primary_modifier_text();
|
|
let (primary_modifier_text, primary_modifier_start_position) =
|
|
if cols >= WIDTH_BREAKPOINTS.0 {
|
|
(format!("Primary: {}", primary_modifier_key_text), 9)
|
|
} else {
|
|
(format!("{}", primary_modifier_key_text), 0)
|
|
};
|
|
print_text_with_coordinates(
|
|
Text::new(primary_modifier_text).color_range(3, primary_modifier_start_position..),
|
|
base_x,
|
|
base_y + 4,
|
|
None,
|
|
None,
|
|
);
|
|
print_nested_list_with_coordinates(
|
|
POSSIBLE_MODIFIERS
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(i, m)| {
|
|
let item = if self.primary_modifier.contains(m) {
|
|
NestedListItem::new(m.to_string()).color_range(3, ..)
|
|
} else {
|
|
NestedListItem::new(m.to_string())
|
|
};
|
|
if self.browsing_primary_modifier && self.selected_primary_key_index == i {
|
|
item.selected()
|
|
} else {
|
|
item
|
|
}
|
|
})
|
|
.collect(),
|
|
base_x,
|
|
base_y + 5,
|
|
Some(screen_width / 2),
|
|
None,
|
|
);
|
|
}
|
|
pub fn render_screen_title_unlock_first(&self, rows: usize, cols: usize) {
|
|
let screen_width = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
WIDTH_BREAKPOINTS.0
|
|
} else {
|
|
WIDTH_BREAKPOINTS.1
|
|
};
|
|
let leader_keys_text = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
"Rebind leader keys (Non-Colliding preset)"
|
|
} else if cols >= WIDTH_BREAKPOINTS.1 {
|
|
"Rebind leader keys (Non-Colliding)"
|
|
} else {
|
|
"Rebind leader keys"
|
|
};
|
|
let base_x = cols.saturating_sub(screen_width) / 2;
|
|
let base_y = rows.saturating_sub(10) / 2;
|
|
let explanation_text_1 = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
"Unlock toggle - used to expose the other modes (eg. PANE, TAB)"
|
|
} else if cols >= WIDTH_BREAKPOINTS.1 {
|
|
"Unlock toggle - expose other modes"
|
|
} else {
|
|
""
|
|
};
|
|
let explanation_text_2 = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
"Secondary modifier - prefixes common actions (eg. New Pane)"
|
|
} else if cols >= WIDTH_BREAKPOINTS.1 {
|
|
"Secondary modifier - common actions"
|
|
} else {
|
|
""
|
|
};
|
|
print_text_with_coordinates(
|
|
Text::new(leader_keys_text).color_range(2, ..),
|
|
base_x,
|
|
base_y,
|
|
None,
|
|
None,
|
|
);
|
|
print_text_with_coordinates(
|
|
Text::new(explanation_text_1).color_range(1, ..=12),
|
|
base_x,
|
|
base_y + 2,
|
|
None,
|
|
None,
|
|
);
|
|
print_text_with_coordinates(
|
|
Text::new(explanation_text_2).color_range(1, ..=17),
|
|
base_x,
|
|
base_y + 3,
|
|
None,
|
|
None,
|
|
);
|
|
}
|
|
fn render_screen_title_default_preset(&self, rows: usize, cols: usize) {
|
|
let screen_width = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
WIDTH_BREAKPOINTS.0
|
|
} else {
|
|
WIDTH_BREAKPOINTS.1
|
|
};
|
|
let leader_keys_text = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
"Rebind leader keys (Default preset)"
|
|
} else {
|
|
"Rebind leader keys"
|
|
};
|
|
let base_x = cols.saturating_sub(screen_width) / 2;
|
|
let base_y = rows.saturating_sub(10) / 2;
|
|
let explanation_text_1 = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
"Primary - the modifier used to switch modes (eg. PANE, TAB)"
|
|
} else if cols >= WIDTH_BREAKPOINTS.1 {
|
|
"Primary - used to switch modes"
|
|
} else {
|
|
""
|
|
};
|
|
let explanation_text_2 = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
"Secondary - the modifier used for common actions (eg. New Pane)"
|
|
} else if cols >= WIDTH_BREAKPOINTS.1 {
|
|
"Secondary - common actions"
|
|
} else {
|
|
""
|
|
};
|
|
print_text_with_coordinates(
|
|
Text::new(leader_keys_text).color_range(2, ..),
|
|
base_x,
|
|
base_y,
|
|
None,
|
|
None,
|
|
);
|
|
print_text_with_coordinates(
|
|
Text::new(explanation_text_1).color_range(1, ..=6),
|
|
base_x,
|
|
base_y + 2,
|
|
None,
|
|
None,
|
|
);
|
|
print_text_with_coordinates(
|
|
Text::new(explanation_text_2).color_range(1, ..=8),
|
|
base_x,
|
|
base_y + 3,
|
|
None,
|
|
None,
|
|
);
|
|
}
|
|
fn render_unlock_toggle(&self, rows: usize, cols: usize) {
|
|
let screen_width = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
WIDTH_BREAKPOINTS.0
|
|
} else {
|
|
WIDTH_BREAKPOINTS.1
|
|
};
|
|
let base_x = cols.saturating_sub(screen_width) / 2;
|
|
let base_y = rows.saturating_sub(10) / 2;
|
|
if let Some(main_leader_key_text) = self.main_leader_text() {
|
|
let main_leader_key_text = if self.rebinding_main_leader {
|
|
"...".to_owned()
|
|
} else {
|
|
main_leader_key_text
|
|
};
|
|
let (primary_modifier_text, primary_modifier_start_position) =
|
|
if cols >= WIDTH_BREAKPOINTS.0 {
|
|
(format!("Unlock Toggle: {}", main_leader_key_text), 15)
|
|
} else {
|
|
(format!("{}", main_leader_key_text), 0)
|
|
};
|
|
let mut primary_modifier =
|
|
Text::new(primary_modifier_text).color_range(3, primary_modifier_start_position..);
|
|
if self.main_leader_selected {
|
|
primary_modifier = primary_modifier.selected();
|
|
}
|
|
print_text_with_coordinates(primary_modifier, base_x, base_y + 5, None, None);
|
|
if self.rebinding_main_leader {
|
|
let first_bulletin = "[Enter new key] eg.";
|
|
let second_bulletin = "\"Ctrl g\", \"Alt g\",";
|
|
let third_bulletin = "\"Alt ESC\", \"Ctrl SPACE\"";
|
|
print_nested_list_with_coordinates(
|
|
vec![
|
|
NestedListItem::new(first_bulletin).color_range(3, ..=14),
|
|
NestedListItem::new(second_bulletin),
|
|
NestedListItem::new(third_bulletin),
|
|
],
|
|
base_x,
|
|
base_y + 6,
|
|
None,
|
|
None,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
fn main_leader_text(&self) -> Option<String> {
|
|
self.main_leader.as_ref().map(|m| format!("{}", m))
|
|
}
|
|
fn render_secondary_modifier_selector(&mut self, rows: usize, cols: usize) {
|
|
let screen_width = if cols >= WIDTH_BREAKPOINTS.0 {
|
|
WIDTH_BREAKPOINTS.0
|
|
} else {
|
|
WIDTH_BREAKPOINTS.1
|
|
};
|
|
let base_x = cols.saturating_sub(screen_width) / 2;
|
|
let base_y = rows.saturating_sub(10) / 2;
|
|
let secondary_modifier_key_text = self.secondary_modifier_text();
|
|
let (secondary_modifier_text, secondary_modifier_start_position) =
|
|
if cols >= WIDTH_BREAKPOINTS.0 {
|
|
if self.currently_in_unlock_first() {
|
|
(
|
|
format!("Secondary Modifier: {}", secondary_modifier_key_text),
|
|
20,
|
|
)
|
|
} else {
|
|
(format!("Secondary: {}", secondary_modifier_key_text), 11)
|
|
}
|
|
} else {
|
|
(format!("{}", secondary_modifier_key_text), 0)
|
|
};
|
|
let secondary_modifier_menu_x_coords = base_x + (screen_width / 2);
|
|
print_text_with_coordinates(
|
|
Text::new(secondary_modifier_text).color_range(0, secondary_modifier_start_position..),
|
|
secondary_modifier_menu_x_coords,
|
|
base_y + 5,
|
|
None,
|
|
None,
|
|
);
|
|
print_nested_list_with_coordinates(
|
|
POSSIBLE_MODIFIERS
|
|
.iter()
|
|
.enumerate()
|
|
.map(|(i, m)| {
|
|
let item = if self.secondary_modifier.contains(m) {
|
|
NestedListItem::new(m.to_string()).color_range(0, ..)
|
|
} else {
|
|
NestedListItem::new(m.to_string())
|
|
};
|
|
if self.browsing_secondary_modifier && self.selected_secondary_key_index == i {
|
|
item.selected()
|
|
} else {
|
|
item
|
|
}
|
|
})
|
|
.collect(),
|
|
secondary_modifier_menu_x_coords,
|
|
base_y + 6,
|
|
Some(screen_width / 2),
|
|
None,
|
|
);
|
|
}
|
|
fn primary_modifier_text(&self) -> String {
|
|
if self.primary_modifier.is_empty() {
|
|
"<UNBOUND>".to_owned()
|
|
} else {
|
|
self.primary_modifier
|
|
.iter()
|
|
.map(|m| m.to_string())
|
|
.collect::<Vec<_>>()
|
|
.join("-")
|
|
}
|
|
}
|
|
fn secondary_modifier_text(&self) -> String {
|
|
if self.secondary_modifier.is_empty() {
|
|
"<UNBOUND>".to_owned()
|
|
} else {
|
|
self.secondary_modifier
|
|
.iter()
|
|
.map(|m| m.to_string())
|
|
.collect::<Vec<_>>()
|
|
.join("-")
|
|
}
|
|
}
|
|
fn render_help_text(&self, rows: usize, cols: usize) {
|
|
if self.is_rebinding_for_presets {
|
|
return self.render_help_text_for_presets_rebinding(rows, cols);
|
|
}
|
|
let help_text_long = "Help: <←↓↑→> - navigate, <SPACE> - select, <ENTER> - apply, <INSERT> - save, <Ctrl c> - reset, <ESC> - close";
|
|
let help_text_medium = "Help: <←↓↑→/SPACE> - navigate/select, <ENTER/INS> - apply/save, <Ctrl c> - reset, <ESC> - close";
|
|
let help_text_short = "Help: <←↓↑→>/<SPACE>/<ENTER> select/<INS> save/<Ctrl c> reset/<ESC>";
|
|
let help_text_minimum = "<←↓↑→>/<SPACE>/<ENTER>/<INS>/<Ctrl c>/<ESC>";
|
|
if cols >= help_text_long.chars().count() {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_long)
|
|
.color_range(2, 6..=12)
|
|
.color_range(2, 25..=31)
|
|
.color_range(2, 43..=49)
|
|
.color_range(2, 60..=67)
|
|
.color_range(2, 77..=84)
|
|
.color_range(2, 95..=99),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
} else if cols >= help_text_medium.chars().count() {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_medium)
|
|
.color_range(2, 6..=17)
|
|
.color_range(2, 38..=48)
|
|
.color_range(2, 64..=72)
|
|
.color_range(2, 82..=86),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
} else if cols >= help_text_short.chars().count() {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_short)
|
|
.color_range(2, 6..=11)
|
|
.color_range(2, 13..=19)
|
|
.color_range(2, 21..=27)
|
|
.color_range(2, 36..=40)
|
|
.color_range(2, 47..=54)
|
|
.color_range(2, 62..=66),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
} else {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_minimum)
|
|
.color_range(2, ..=5)
|
|
.color_range(2, 7..=13)
|
|
.color_range(2, 15..=21)
|
|
.color_range(2, 23..=27)
|
|
.color_range(2, 29..=36)
|
|
.color_range(2, 38..=42),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
}
|
|
}
|
|
fn render_help_text_for_presets_rebinding(&self, rows: usize, cols: usize) {
|
|
let help_text_long = "Help: <←↓↑→> - navigate, <SPACE> - select, <ENTER> - apply to presets in previous screen";
|
|
let help_text_medium = "Help: <←↓↑→> - navigate, <SPACE> - select, <ENTER> - apply";
|
|
let help_text_short = "<←↓↑→/SPACE> - navigate/select, <ENTER> - apply";
|
|
let help_text_minimum = "<←↓↑→>/<SPACE>/<ENTER>";
|
|
if cols >= help_text_long.chars().count() {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_long)
|
|
.color_range(2, 6..=12)
|
|
.color_range(2, 25..=31)
|
|
.color_range(2, 43..=49),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
} else if cols >= help_text_medium.chars().count() {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_medium)
|
|
.color_range(2, 6..=12)
|
|
.color_range(2, 25..=31)
|
|
.color_range(2, 43..=49),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
} else if cols >= help_text_short.chars().count() {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_short)
|
|
.color_range(2, 1..=4)
|
|
.color_range(2, 6..=10)
|
|
.color_range(2, 32..=38),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
} else {
|
|
print_text_with_coordinates(
|
|
Text::new(help_text_minimum)
|
|
.color_range(2, ..=5)
|
|
.color_range(2, 7..=13)
|
|
.color_range(2, 15..=21),
|
|
0,
|
|
rows,
|
|
None,
|
|
None,
|
|
);
|
|
}
|
|
}
|
|
pub fn handle_key(&mut self, key: KeyWithModifier) -> bool {
|
|
if let Some(notification) = self.notification.take() {
|
|
drop(notification);
|
|
true
|
|
} else if self.currently_in_unlock_first() {
|
|
self.handle_unlock_first_key(key)
|
|
} else {
|
|
self.handle_default_preset_key(key)
|
|
}
|
|
}
|
|
fn currently_in_unlock_first(&self) -> bool {
|
|
if self.is_rebinding_for_presets {
|
|
false
|
|
} else {
|
|
self.latest_mode_info
|
|
.as_ref()
|
|
.map(|m| m.base_mode == Some(InputMode::Locked))
|
|
.unwrap_or(false)
|
|
}
|
|
}
|
|
fn handle_default_preset_key(&mut self, key: KeyWithModifier) -> bool {
|
|
let should_render = true;
|
|
if key.bare_key == BareKey::Insert
|
|
&& key.has_no_modifiers()
|
|
&& !self.is_rebinding_for_presets
|
|
{
|
|
let write_to_disk = true;
|
|
self.rebind_keys(write_to_disk);
|
|
self.hard_reset_ui_state();
|
|
} else if key.bare_key == BareKey::Enter && key.has_no_modifiers() {
|
|
let write_to_disk = false;
|
|
self.rebind_keys(write_to_disk);
|
|
self.hard_reset_ui_state();
|
|
} else if key.is_key_with_ctrl_modifier(BareKey::Char('c')) {
|
|
self.hard_reset_ui_state();
|
|
} else if key.bare_key == BareKey::Esc && key.has_no_modifiers() {
|
|
close_self();
|
|
} else if key.bare_key == BareKey::Char(' ') && key.has_no_modifiers() {
|
|
if self.browsing_primary_modifier {
|
|
let selected_primary_key_index = self.selected_primary_key_index;
|
|
self.toggle_primary_modifier(selected_primary_key_index);
|
|
} else if self.browsing_secondary_modifier {
|
|
let selected_secondary_key_index = self.selected_secondary_key_index;
|
|
self.toggle_secondary_modifier(selected_secondary_key_index);
|
|
}
|
|
} else if (key.bare_key == BareKey::Left
|
|
|| key.bare_key == BareKey::Right
|
|
|| key.bare_key == BareKey::Up
|
|
|| key.bare_key == BareKey::Down)
|
|
&& key.has_no_modifiers()
|
|
{
|
|
self.move_selection_for_default_preset(&key);
|
|
} else if self.rebinding_main_leader {
|
|
self.soft_reset_ui_state();
|
|
self.main_leader = Some(key.clone());
|
|
self.ui_is_dirty = true;
|
|
}
|
|
should_render
|
|
}
|
|
fn toggle_secondary_modifier(&mut self, secondary_modifier_index: usize) {
|
|
if let Some(selected_modifier) = POSSIBLE_MODIFIERS.get(secondary_modifier_index) {
|
|
if self.secondary_modifier.contains(selected_modifier) {
|
|
self.secondary_modifier.remove(selected_modifier);
|
|
} else {
|
|
self.secondary_modifier.insert(*selected_modifier);
|
|
}
|
|
self.ui_is_dirty = true;
|
|
}
|
|
}
|
|
fn toggle_primary_modifier(&mut self, primary_modifier_index: usize) {
|
|
if let Some(selected_modifier) = POSSIBLE_MODIFIERS.get(primary_modifier_index) {
|
|
if self.primary_modifier.contains(selected_modifier) {
|
|
self.primary_modifier.remove(selected_modifier);
|
|
} else {
|
|
self.primary_modifier.insert(*selected_modifier);
|
|
}
|
|
self.ui_is_dirty = true;
|
|
}
|
|
}
|
|
fn rebind_keys(&mut self, write_to_disk: bool) {
|
|
let mut keys_to_unbind = vec![];
|
|
let mut keys_to_bind = vec![];
|
|
if self.currently_in_unlock_first() {
|
|
if let Some(unlock_key) = &self.main_leader {
|
|
self.bind_unlock_key(&mut keys_to_unbind, &mut keys_to_bind, unlock_key);
|
|
}
|
|
self.bind_all_secondary_actions(&mut keys_to_unbind, &mut keys_to_bind);
|
|
} else {
|
|
self.bind_all_secondary_actions(&mut keys_to_unbind, &mut keys_to_bind);
|
|
self.bind_all_primary_actions(&mut keys_to_unbind, &mut keys_to_bind);
|
|
}
|
|
if write_to_disk {
|
|
self.notification = Some("Configuration applied and saved to disk.".to_owned());
|
|
} else {
|
|
self.notification = Some("Configuration applied to current session.".to_owned());
|
|
}
|
|
rebind_keys(keys_to_unbind, keys_to_bind, write_to_disk);
|
|
}
|
|
fn bind_all_primary_actions(
|
|
&self,
|
|
keys_to_unbind: &mut Vec<(InputMode, KeyWithModifier)>,
|
|
keys_to_bind: &mut Vec<(InputMode, KeyWithModifier, Vec<actions::Action>)>,
|
|
) {
|
|
self.bind_primary_switch_to_mode_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
InputMode::Locked,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('g'), self.primary_modifier.clone()),
|
|
);
|
|
self.bind_primary_switch_to_mode_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
InputMode::Pane,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('p'), self.primary_modifier.clone()),
|
|
);
|
|
self.bind_primary_switch_to_mode_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
InputMode::Tab,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('t'), self.primary_modifier.clone()),
|
|
);
|
|
self.bind_primary_switch_to_mode_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
InputMode::Resize,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('n'), self.primary_modifier.clone()),
|
|
);
|
|
self.bind_primary_switch_to_mode_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
InputMode::Move,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('h'), self.primary_modifier.clone()),
|
|
);
|
|
self.bind_primary_switch_to_mode_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
InputMode::Scroll,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('s'), self.primary_modifier.clone()),
|
|
);
|
|
self.bind_primary_switch_to_mode_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
InputMode::Session,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('o'), self.primary_modifier.clone()),
|
|
);
|
|
self.bind_quit_action(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
KeyWithModifier::new_with_modifiers(BareKey::Char('q'), self.primary_modifier.clone()),
|
|
);
|
|
}
|
|
fn bind_quit_action(
|
|
&self,
|
|
keys_to_unbind: &mut Vec<(InputMode, KeyWithModifier)>,
|
|
keys_to_bind: &mut Vec<(InputMode, KeyWithModifier, Vec<actions::Action>)>,
|
|
new_key: KeyWithModifier,
|
|
) {
|
|
let all_relevant_modes = vec![
|
|
InputMode::Normal,
|
|
InputMode::Pane,
|
|
InputMode::Tab,
|
|
InputMode::Resize,
|
|
InputMode::Move,
|
|
InputMode::Search,
|
|
InputMode::Scroll,
|
|
InputMode::Session,
|
|
];
|
|
for mode in &all_relevant_modes {
|
|
for current_keybind in self.get_current_keybinds(*mode, &[actions::Action::Quit]) {
|
|
keys_to_unbind.push((*mode, current_keybind));
|
|
}
|
|
keys_to_bind.push((*mode, new_key.clone(), vec![actions::Action::Quit]));
|
|
}
|
|
}
|
|
fn get_current_keybinds(
|
|
&self,
|
|
in_mode: InputMode,
|
|
actions: &[actions::Action],
|
|
) -> Vec<KeyWithModifier> {
|
|
self.latest_mode_info
|
|
.as_ref()
|
|
.and_then(|m_i| {
|
|
m_i.keybinds
|
|
.iter()
|
|
.find_map(|m| if m.0 == in_mode { Some(&m.1) } else { None })
|
|
})
|
|
.map(|k| {
|
|
k.into_iter()
|
|
.filter_map(|(k, a)| if a == actions { Some(k.clone()) } else { None })
|
|
.collect::<Vec<_>>()
|
|
})
|
|
.unwrap_or_else(Default::default)
|
|
}
|
|
fn bind_primary_switch_to_mode_action(
|
|
&self,
|
|
keys_to_unbind: &mut Vec<(InputMode, KeyWithModifier)>,
|
|
keys_to_bind: &mut Vec<(InputMode, KeyWithModifier, Vec<actions::Action>)>,
|
|
target_mode: InputMode,
|
|
new_key: KeyWithModifier,
|
|
) {
|
|
let all_relevant_modes = vec![
|
|
InputMode::Locked,
|
|
InputMode::Normal,
|
|
InputMode::Pane,
|
|
InputMode::Tab,
|
|
InputMode::Resize,
|
|
InputMode::Move,
|
|
InputMode::Search,
|
|
InputMode::Scroll,
|
|
InputMode::Session,
|
|
];
|
|
for mode in &all_relevant_modes {
|
|
if mode == &target_mode {
|
|
for current_keybind in self.get_current_keybinds(
|
|
*mode,
|
|
&[actions::Action::SwitchToMode(InputMode::Normal)],
|
|
) {
|
|
if current_keybind.bare_key != BareKey::Enter
|
|
&& current_keybind.bare_key != BareKey::Esc
|
|
{
|
|
keys_to_unbind.push((*mode, current_keybind));
|
|
}
|
|
}
|
|
} else {
|
|
for current_keybind in
|
|
self.get_current_keybinds(*mode, &[actions::Action::SwitchToMode(target_mode)])
|
|
{
|
|
keys_to_unbind.push((*mode, current_keybind));
|
|
}
|
|
}
|
|
}
|
|
for mode in &all_relevant_modes {
|
|
if mode == &target_mode {
|
|
keys_to_bind.push((
|
|
*mode,
|
|
new_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Normal)],
|
|
));
|
|
} else if mode != &InputMode::Locked {
|
|
keys_to_bind.push((
|
|
*mode,
|
|
new_key.clone(),
|
|
vec![actions::Action::SwitchToMode(target_mode)],
|
|
));
|
|
}
|
|
}
|
|
}
|
|
fn bind_all_secondary_actions(
|
|
&self,
|
|
keys_to_unbind: &mut Vec<(InputMode, KeyWithModifier)>,
|
|
keys_to_bind: &mut Vec<(InputMode, KeyWithModifier, Vec<actions::Action>)>,
|
|
) {
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::NewPane(None, None, false)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('n'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::ToggleFloatingPanes],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('f'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveTab(Direction::Left)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('i'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveTab(Direction::Right)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('o'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocusOrTab(Direction::Left)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('h'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocusOrTab(Direction::Left)],
|
|
KeyWithModifier::new_with_modifiers(BareKey::Left, self.secondary_modifier.clone()),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocusOrTab(Direction::Right)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('l'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocusOrTab(Direction::Right)],
|
|
KeyWithModifier::new_with_modifiers(BareKey::Right, self.secondary_modifier.clone()),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocus(Direction::Down)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('j'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocus(Direction::Down)],
|
|
KeyWithModifier::new_with_modifiers(BareKey::Down, self.secondary_modifier.clone()),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocus(Direction::Up)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('k'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::MoveFocus(Direction::Up)],
|
|
KeyWithModifier::new_with_modifiers(BareKey::Up, self.secondary_modifier.clone()),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::Resize(Resize::Increase, None)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('+'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::Resize(Resize::Increase, None)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('='),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::Resize(Resize::Decrease, None)],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('-'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::PreviousSwapLayout],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char('['),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
self.bind_actions(
|
|
keys_to_unbind,
|
|
keys_to_bind,
|
|
&[actions::Action::NextSwapLayout],
|
|
KeyWithModifier::new_with_modifiers(
|
|
BareKey::Char(']'),
|
|
self.secondary_modifier.clone(),
|
|
),
|
|
);
|
|
}
|
|
fn bind_actions(
|
|
&self,
|
|
keys_to_unbind: &mut Vec<(InputMode, KeyWithModifier)>,
|
|
keys_to_bind: &mut Vec<(InputMode, KeyWithModifier, Vec<actions::Action>)>,
|
|
actions: &[actions::Action],
|
|
key: KeyWithModifier,
|
|
) {
|
|
for current_keybind in self.get_current_keybinds(InputMode::Normal, actions) {
|
|
keys_to_unbind.push((InputMode::Normal, current_keybind));
|
|
}
|
|
for current_keybind in self.get_current_keybinds(InputMode::Locked, actions) {
|
|
keys_to_unbind.push((InputMode::Locked, current_keybind));
|
|
}
|
|
keys_to_bind.push((InputMode::Normal, key.clone(), actions.to_vec()));
|
|
keys_to_bind.push((InputMode::Locked, key, actions.to_vec()));
|
|
}
|
|
fn bind_unlock_key(
|
|
&self,
|
|
keys_to_unbind: &mut Vec<(InputMode, KeyWithModifier)>,
|
|
keys_to_bind: &mut Vec<(InputMode, KeyWithModifier, Vec<actions::Action>)>,
|
|
unlock_key: &KeyWithModifier,
|
|
) {
|
|
if let Some(previous_unlock_key) = self.get_current_keybind(
|
|
InputMode::Locked,
|
|
&[actions::Action::SwitchToMode(InputMode::Normal)],
|
|
) {
|
|
keys_to_unbind.push((InputMode::Locked, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Normal, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Pane, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Tab, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Resize, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Move, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Search, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Scroll, previous_unlock_key.clone()));
|
|
keys_to_unbind.push((InputMode::Session, previous_unlock_key.clone()));
|
|
}
|
|
keys_to_bind.push((
|
|
InputMode::Locked,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Normal)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Normal,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Pane,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Tab,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Resize,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Move,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Search,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Scroll,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
keys_to_bind.push((
|
|
InputMode::Session,
|
|
unlock_key.clone(),
|
|
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
|
));
|
|
}
|
|
fn get_current_keybind(
|
|
&self,
|
|
in_mode: InputMode,
|
|
actions: &[actions::Action],
|
|
) -> Option<KeyWithModifier> {
|
|
self.latest_mode_info
|
|
.as_ref()
|
|
.and_then(|m_i| {
|
|
m_i.keybinds
|
|
.iter()
|
|
.find_map(|m| if m.0 == in_mode { Some(&m.1) } else { None })
|
|
})
|
|
.and_then(|k| {
|
|
k.into_iter()
|
|
.find_map(|(k, a)| if a == actions { Some(k) } else { None })
|
|
})
|
|
.cloned()
|
|
}
|
|
fn soft_reset_ui_state(&mut self) {
|
|
let mut latest_mode_info = self.latest_mode_info.take();
|
|
let notification = self.notification.take();
|
|
let primary_modifier = self.primary_modifier.clone();
|
|
let secondary_modifier = self.secondary_modifier.clone();
|
|
let main_leader = self.main_leader.clone();
|
|
let ui_is_dirty = self.ui_is_dirty;
|
|
let is_rebinding_for_presets = self.is_rebinding_for_presets;
|
|
*self = Default::default();
|
|
if let Some(latest_mode_info) = latest_mode_info.take() {
|
|
self.update_mode_info(latest_mode_info);
|
|
}
|
|
self.notification = notification;
|
|
self.primary_modifier = primary_modifier;
|
|
self.secondary_modifier = secondary_modifier;
|
|
self.main_leader = main_leader;
|
|
self.ui_is_dirty = ui_is_dirty;
|
|
self.is_rebinding_for_presets = is_rebinding_for_presets;
|
|
}
|
|
fn hard_reset_ui_state(&mut self) {
|
|
let mut latest_mode_info = self.latest_mode_info.take();
|
|
let notification = self.notification.take();
|
|
let is_rebinding_for_presets = self.is_rebinding_for_presets;
|
|
*self = Default::default();
|
|
if let Some(latest_mode_info) = latest_mode_info.take() {
|
|
self.update_mode_info(latest_mode_info);
|
|
}
|
|
self.notification = notification;
|
|
self.is_rebinding_for_presets = is_rebinding_for_presets;
|
|
}
|
|
fn handle_unlock_first_key(&mut self, key: KeyWithModifier) -> bool {
|
|
if key.bare_key == BareKey::Insert
|
|
&& key.has_no_modifiers()
|
|
&& !self.is_rebinding_for_presets
|
|
{
|
|
let write_to_disk = true;
|
|
self.rebind_keys(write_to_disk);
|
|
self.hard_reset_ui_state();
|
|
} else if key.bare_key == BareKey::Enter && key.has_no_modifiers() {
|
|
let write_to_disk = false;
|
|
self.rebind_keys(write_to_disk);
|
|
self.hard_reset_ui_state();
|
|
} else if key.is_key_with_ctrl_modifier(BareKey::Char('c')) {
|
|
self.hard_reset_ui_state();
|
|
} else if key.bare_key == BareKey::Esc && key.has_no_modifiers() {
|
|
if self.rebinding_main_leader {
|
|
self.soft_reset_ui_state();
|
|
} else {
|
|
close_self();
|
|
}
|
|
} else if key.bare_key == BareKey::Char(' ') && key.has_no_modifiers() {
|
|
if self.main_leader_selected {
|
|
self.set_rebinding_unlock_toggle();
|
|
} else if self.browsing_secondary_modifier {
|
|
let selected_secondary_key_index = self.selected_secondary_key_index;
|
|
self.toggle_secondary_modifier(selected_secondary_key_index);
|
|
}
|
|
} else if (key.bare_key == BareKey::Left
|
|
|| key.bare_key == BareKey::Right
|
|
|| key.bare_key == BareKey::Up
|
|
|| key.bare_key == BareKey::Down)
|
|
&& key.has_no_modifiers()
|
|
{
|
|
self.move_selection_for_unlock_first(&key);
|
|
} else if self.rebinding_main_leader {
|
|
self.soft_reset_ui_state();
|
|
self.main_leader = Some(key.clone());
|
|
self.ui_is_dirty = true;
|
|
}
|
|
true
|
|
}
|
|
fn warning_text(&self, max_width: usize) -> Option<String> {
|
|
if self.needs_kitty_support() {
|
|
if max_width >= 38 {
|
|
Some(String::from("Warning: requires supporting terminal."))
|
|
} else {
|
|
Some(String::from("Requires supporting terminal"))
|
|
}
|
|
} else if self.primary_modifier.is_empty() && self.secondary_modifier.is_empty() {
|
|
if max_width >= 49 {
|
|
Some(String::from(
|
|
"Warning: no leaders defined. UI will be disabled.",
|
|
))
|
|
} else {
|
|
Some(String::from("No leaders. UI will be unusable."))
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
fn needs_kitty_support(&self) -> bool {
|
|
self.primary_modifier.len() > 1
|
|
|| self.secondary_modifier.len() > 1
|
|
|| self.primary_modifier.contains(&KeyModifier::Super)
|
|
|| self.secondary_modifier.contains(&KeyModifier::Super)
|
|
}
|
|
}
|