diff --git a/default-plugins/configuration/src/main.rs b/default-plugins/configuration/src/main.rs index 6fde27bd..016dca58 100644 --- a/default-plugins/configuration/src/main.rs +++ b/default-plugins/configuration/src/main.rs @@ -1,56 +1,78 @@ +mod presets; +mod presets_screen; +mod rebind_leaders_screen; +mod ui_components; + use zellij_tile::prelude::*; -use std::collections::{BTreeMap, BTreeSet}; +use presets_screen::PresetsScreen; +use rebind_leaders_screen::RebindLeadersScreen; +use ui_components::top_tab_menu; -static UI_SIZE: usize = 15; +use std::collections::BTreeMap; + +pub static UI_SIZE: usize = 15; +pub static WIDTH_BREAKPOINTS: (usize, usize) = (62, 35); +pub static POSSIBLE_MODIFIERS: [KeyModifier; 4] = [ + KeyModifier::Ctrl, + KeyModifier::Alt, + KeyModifier::Super, + KeyModifier::Shift, +]; + +#[derive(Debug)] +enum Screen { + RebindLeaders(RebindLeadersScreen), + Presets(PresetsScreen), +} + +impl Screen { + pub fn reset_state(&mut self, is_setup_wizard: bool) { + if is_setup_wizard { + Screen::new_reset_keybindings_screen(Some(0)); + } else { + match self { + Screen::RebindLeaders(r) => *r = Default::default(), + Screen::Presets(r) => *r = Default::default(), + } + } + } + pub fn update_mode_info(&mut self, latest_mode_info: ModeInfo) { + match self { + Screen::RebindLeaders(r) => r.update_mode_info(latest_mode_info), + Screen::Presets(r) => r.update_mode_info(latest_mode_info), + } + } +} + +impl Default for Screen { + fn default() -> Self { + Screen::RebindLeaders(Default::default()) + } +} + +impl Screen { + pub fn new_reset_keybindings_screen(selected_index: Option) -> Self { + Screen::Presets(PresetsScreen::new(selected_index)) + } +} struct State { - userspace_configuration: BTreeMap, - selected_index: Option, - selected_primary_key_index: usize, - selected_secondary_key_index: usize, - remapping_leaders: bool, - primary_modifier: BTreeSet, - secondary_modifier: BTreeSet, - possible_modifiers: Vec, - browsing_secondary_modifier: bool, - mode_color_index: usize, - preset_color_index: usize, - primary_leader_key_color_index: usize, - secondary_leader_key_color_index: usize, notification: Option, is_setup_wizard: bool, ui_size: usize, + current_screen: Screen, + latest_mode_info: Option, } impl Default for State { 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); State { - userspace_configuration: BTreeMap::new(), - selected_index: None, - selected_primary_key_index: 0, - selected_secondary_key_index: 0, - remapping_leaders: false, - primary_modifier, - secondary_modifier, - possible_modifiers: vec![ - KeyModifier::Ctrl, - KeyModifier::Alt, - KeyModifier::Super, - KeyModifier::Shift, - ], - browsing_secondary_modifier: false, - primary_leader_key_color_index: 3, - secondary_leader_key_color_index: 0, - mode_color_index: 2, - preset_color_index: 1, notification: None, is_setup_wizard: false, ui_size: UI_SIZE, + current_screen: Screen::default(), + latest_mode_info: None, } } } @@ -63,12 +85,15 @@ impl ZellijPlugin for State { .get("is_setup_wizard") .map(|v| v == "true") .unwrap_or(false); - self.userspace_configuration = configuration; - subscribe(&[EventType::Key, EventType::FailedToWriteConfigToDisk]); + subscribe(&[ + EventType::Key, + EventType::FailedToWriteConfigToDisk, + EventType::ModeUpdate, + ]); let own_plugin_id = get_plugin_ids().plugin_id; if self.is_setup_wizard { self.ui_size = 18; - self.selected_index = Some(0); + self.current_screen = Screen::new_reset_keybindings_screen(Some(0)); rename_plugin_pane(own_plugin_id, "First Run Setup Wizard (Step 1/1)"); resize_focused_pane(Resize::Increase); resize_focused_pane(Resize::Increase); @@ -80,13 +105,38 @@ impl ZellijPlugin for State { fn update(&mut self, event: Event) -> bool { let mut should_render = false; match event { + Event::ModeUpdate(mode_info) => { + if self.latest_mode_info.as_ref().and_then(|l| l.base_mode) != mode_info.base_mode { + // reset ui state + self.current_screen.reset_state(self.is_setup_wizard); + } + self.latest_mode_info = Some(mode_info.clone()); + self.current_screen.update_mode_info(mode_info.clone()); + should_render = true; + }, Event::Key(key) => { - if self.remapping_leaders { - should_render = self.handle_remapping_screen_key(key); - } else if self.is_setup_wizard { - should_render = self.handle_setup_wizard_key(key); + if self.notification.is_some() { + self.notification = None; + should_render = true; + } else if key.bare_key == BareKey::Tab + && key.has_no_modifiers() + && !self.is_setup_wizard + { + self.switch_screen(); + should_render = true; } else { - should_render = self.handle_main_screen_key(key); + should_render = match &mut self.current_screen { + Screen::RebindLeaders(rebind_leaders_screen) => { + rebind_leaders_screen.handle_key(key) + }, + Screen::Presets(presets_screen) => { + if self.is_setup_wizard { + presets_screen.handle_setup_wizard_key(key) + } else { + presets_screen.handle_presets_key(key) + } + }, + }; } }, Event::FailedToWriteConfigToDisk(config_file_path) => { @@ -108,2154 +158,61 @@ impl ZellijPlugin for State { should_render } fn render(&mut self, rows: usize, cols: usize) { - if self.remapping_leaders { - self.render_remapping_leaders_screen(rows, cols); - } else if self.is_setup_wizard { - self.render_setup_wizard_screen(rows, cols); - } else { - self.render_main_screen(rows, cols); + let notification = self.notification.clone(); + if self.is_in_main_screen() { + top_tab_menu(cols, &self.current_screen); } + match &mut self.current_screen { + Screen::RebindLeaders(rebind_leaders_screen) => { + rebind_leaders_screen.render(rows, cols, self.ui_size, ¬ification); + }, + Screen::Presets(presets_screen) => { + if self.is_setup_wizard { + presets_screen.render_setup_wizard_screen( + rows, + cols, + self.ui_size, + ¬ification, + ) + } else { + presets_screen.render_reset_keybindings_screen( + rows, + cols, + self.ui_size, + ¬ification, + ) + } + }, + }; } } impl State { - fn handle_remapping_screen_key(&mut self, key: KeyWithModifier) -> bool { - let mut should_render = false; - if self.browsing_secondary_modifier { - if key.bare_key == BareKey::Left && key.has_no_modifiers() { - self.browsing_secondary_modifier = false; - self.selected_primary_key_index = self.selected_secondary_key_index; - should_render = true; - } else if key.bare_key == BareKey::Right && key.has_no_modifiers() { - self.browsing_secondary_modifier = false; - self.selected_primary_key_index = self.selected_secondary_key_index; - should_render = true; - } else if key.bare_key == BareKey::Down && key.has_no_modifiers() { - if self.selected_secondary_key_index - < self.possible_modifiers.len().saturating_sub(1) - { - self.selected_secondary_key_index += 1; + fn is_in_main_screen(&self) -> bool { + match &self.current_screen { + Screen::RebindLeaders(_) => true, + Screen::Presets(presets_screen) => { + if self.is_setup_wizard || presets_screen.rebinding_leaders() { + false } else { - self.selected_secondary_key_index = 0; + true } - should_render = true; - } 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.selected_secondary_key_index = - self.possible_modifiers.len().saturating_sub(1); - } - should_render = true; - } else if key.bare_key == BareKey::Char(' ') && key.has_no_modifiers() { - if let Some(selected_modifier) = self - .possible_modifiers - .get(self.selected_secondary_key_index) - { - if self.secondary_modifier.contains(selected_modifier) { - self.secondary_modifier.remove(selected_modifier); - } else { - self.secondary_modifier.insert(*selected_modifier); - } - should_render = true; - } - } - } else { - if key.bare_key == BareKey::Left && key.has_no_modifiers() { - self.browsing_secondary_modifier = true; - self.selected_secondary_key_index = self.selected_primary_key_index; - should_render = true; - } else if key.bare_key == BareKey::Right && key.has_no_modifiers() { - self.browsing_secondary_modifier = true; - self.selected_secondary_key_index = self.selected_primary_key_index; - should_render = true; - } else if key.bare_key == BareKey::Down && key.has_no_modifiers() { - if self.selected_primary_key_index < self.possible_modifiers.len().saturating_sub(1) - { - self.selected_primary_key_index += 1; - } else { - self.selected_primary_key_index = 0; - } - should_render = true; - } 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 { - self.selected_primary_key_index = - self.possible_modifiers.len().saturating_sub(1); - } - should_render = true; - } else if key.bare_key == BareKey::Char(' ') && key.has_no_modifiers() { - if let Some(selected_modifier) = - self.possible_modifiers.get(self.selected_primary_key_index) - { - if self.primary_modifier.contains(selected_modifier) { - self.primary_modifier.remove(selected_modifier); - } else { - self.primary_modifier.insert(*selected_modifier); - } - should_render = true; - } - } - } - if key.bare_key == BareKey::Enter { - self.remapping_leaders = false; - should_render = true; - } - should_render - } - fn handle_main_screen_key(&mut self, key: KeyWithModifier) -> bool { - let mut should_render = false; - if self.notification.is_some() { - self.notification = None; - should_render = true; - } else if key.bare_key == BareKey::Down && key.has_no_modifiers() { - if self.selected_index.is_none() { - self.selected_index = Some(0); - } else if self.selected_index < Some(1) { - self.selected_index = Some(1); - } else { - self.selected_index = None; - } - should_render = true; - } else if key.bare_key == BareKey::Up && key.has_no_modifiers() { - if self.selected_index.is_none() { - self.selected_index = Some(1); - } else if self.selected_index == Some(1) { - self.selected_index = Some(0); - } else { - self.selected_index = None; - } - should_render = true; - } else if key.bare_key == BareKey::Enter && key.has_no_modifiers() { - if let Some(selected) = self.selected_index.take() { - let write_to_disk = false; - self.reconfigure(selected, write_to_disk); - self.notification = Some("Configuration applied to current session.".to_owned()); - should_render = true; - } else { - self.selected_index = Some(0); - should_render = true; - } - } else if key.bare_key == BareKey::Char(' ') && key.has_no_modifiers() { - if let Some(selected) = self.selected_index.take() { - let write_to_disk = true; - self.reconfigure(selected, write_to_disk); - self.notification = Some("Configuration applied and saved to disk.".to_owned()); - should_render = true; - } - } else if key.bare_key == BareKey::Char('l') && key.has_no_modifiers() { - self.remapping_leaders = true; - should_render = true; - } else if (key.bare_key == BareKey::Esc && key.has_no_modifiers()) - || key.is_key_with_ctrl_modifier(BareKey::Char('c')) - { - close_self(); - should_render = true; - } - should_render - } - fn handle_setup_wizard_key(&mut self, key: KeyWithModifier) -> bool { - let mut should_render = false; - if self.notification.is_some() { - self.notification = None; - should_render = true; - } else if key.bare_key == BareKey::Down && key.has_no_modifiers() { - if self.selected_index.is_none() { - self.selected_index = Some(0); - } else if self.selected_index < Some(1) { - self.selected_index = Some(1); - } else { - self.selected_index = None; - } - should_render = true; - } else if key.bare_key == BareKey::Up && key.has_no_modifiers() { - if self.selected_index.is_none() { - self.selected_index = Some(1); - } else if self.selected_index == Some(1) { - self.selected_index = Some(0); - } else { - self.selected_index = None; - } - should_render = true; - } else if key.bare_key == BareKey::Enter && key.has_no_modifiers() { - if let Some(selected) = self.selected_index.take() { - let write_to_disk = true; - self.reconfigure(selected, write_to_disk); - close_self(); - } else { - self.selected_index = Some(0); - should_render = true; - } - } else if key.bare_key == BareKey::Char('l') && key.has_no_modifiers() { - self.remapping_leaders = true; - should_render = true; - } else if (key.bare_key == BareKey::Esc && key.has_no_modifiers()) - || key.is_key_with_ctrl_modifier(BareKey::Char('c')) - { - close_self(); - should_render = true; - } - should_render - } - fn render_selection_keymap(&self, rows: usize, cols: usize) { - let widths = self.remapping_screen_widths(); - if cols >= widths.0 { - let mut x = cols.saturating_sub(10) / 2; - let mut y = rows.saturating_sub(7) / 2; - if self.browsing_secondary_modifier { - x += 31; - y += self.selected_secondary_key_index; - } else { - y += self.selected_primary_key_index; - } - let text = "<←↓↑→> / "; - let text_len = text.chars().count(); - let text = Text::new(text) - .color_range(2, 1..5) - .color_range(2, 10..15) - .selected(); - print_text_with_coordinates(text, x.saturating_sub(text_len), y + 3, None, None); + }, } } - fn render_remapping_screen_title(&self, rows: usize, cols: usize) { - let widths = self.remapping_screen_widths(); - let screen_width = if cols >= widths.0 { - widths.0 - } else if cols >= widths.1 { - widths.1 - } else { - widths.2 - }; - let leader_keys_text = if cols >= widths.0 { - "Adjust leader keys for the presets in the previous screen:" - } else { - "Adjust leader keys:" - }; - let base_x = cols.saturating_sub(screen_width) / 2; - let base_y = rows.saturating_sub(7) / 2; - print_text_with_coordinates( - Text::new(leader_keys_text).color_range(2, ..), - base_x, - base_y, - None, - None, - ); - } - fn render_primary_modifier_selector(&self, rows: usize, cols: usize) { - let widths = self.remapping_screen_widths(); - let screen_width = if cols >= widths.0 { - widths.0 - } else if cols >= widths.1 { - widths.1 - } else { - widths.2 - }; - self.render_remapping_screen_title(rows, cols); - 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 >= widths.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( - self.primary_leader_key_color_index, - primary_modifier_start_position.., - ), - base_x, - base_y + 2, - None, - None, - ); - print_nested_list_with_coordinates( - self.possible_modifiers - .iter() - .enumerate() - .map(|(i, m)| { - let item = if self.primary_modifier.contains(m) { - NestedListItem::new(m.to_string()) - .color_range(self.primary_leader_key_color_index, ..) - } else { - NestedListItem::new(m.to_string()) - }; - if !self.browsing_secondary_modifier && self.selected_primary_key_index == i { - item.selected() - } else { - item - } - }) - .collect(), - base_x, - base_y + 3, - Some(screen_width / 2), - None, - ); - } - fn render_secondary_modifier_selector(&mut self, rows: usize, cols: usize) { - let widths = self.remapping_screen_widths(); - let screen_width = if cols >= widths.0 { - widths.0 - } else if cols >= widths.1 { - widths.1 - } else { - widths.2 - }; - let base_x = cols.saturating_sub(screen_width) / 2; - let base_y = rows.saturating_sub(7) / 2; - let secondary_modifier_key_text = self.secondary_modifier_text(); - let (secondary_modifier_text, secondary_modifier_start_position) = if cols >= widths.0 { - (format!("Secondary: {}", secondary_modifier_key_text), 10) - } 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( - self.secondary_leader_key_color_index, - secondary_modifier_start_position.., - ), - secondary_modifier_menu_x_coords, - base_y + 2, - None, - None, - ); - print_nested_list_with_coordinates( - self.possible_modifiers - .iter() - .enumerate() - .map(|(i, m)| { - let item = if self.secondary_modifier.contains(m) { - NestedListItem::new(m.to_string()) - .color_range(self.secondary_leader_key_color_index, ..) - } 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 + 3, - Some(screen_width / 2), - None, - ); - } - fn render_remapping_leaders_screen(&mut self, rows: usize, cols: usize) { - self.render_remapping_screen_title(rows, cols); - self.render_primary_modifier_selector(rows, cols); - self.render_secondary_modifier_selector(rows, cols); - self.render_selection_keymap(rows, cols); - self.render_help_text_remapping(rows, cols); - } - fn render_override_title(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) { - let widths = self.main_screen_widths(primary_modifier_key_text); - if cols >= widths.0 { - let title_text = "Override keybindings with one of the following presets:"; - let left_padding = cols.saturating_sub(widths.0) / 2; - print_text_with_coordinates( - Text::new(title_text).color_range(2, ..), - left_padding, - rows.saturating_sub(self.ui_size) / 2, - None, - None, - ); - } else { - let title_text = "Override keybindings:"; - let left_padding = if cols >= widths.1 { - cols.saturating_sub(widths.1) / 2 - } else { - cols.saturating_sub(widths.2) / 2 - }; - print_text_with_coordinates( - Text::new(title_text).color_range(2, ..), - left_padding, - rows.saturating_sub(self.ui_size) / 2, - None, - None, - ); + fn switch_screen(&mut self) { + match &self.current_screen { + Screen::RebindLeaders(_) => { + self.current_screen = Screen::Presets(Default::default()); + }, + Screen::Presets(_) => { + self.current_screen = Screen::RebindLeaders( + RebindLeadersScreen::default().with_mode_info(self.latest_mode_info.clone()), + ); + }, } - } - fn render_setup_wizard_title(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) { - let widths = self.main_screen_widths(primary_modifier_key_text); - if cols >= widths.0 { - let title_text_1 = "Hi there! How would you like to interact with Zellij?"; - let title_text_2 = "Not sure? Press to choose Default."; - let title_text_3 = "Everything can always be changed later."; - let title_text_4 = "Tips appear on screen - you don't need to remember anything."; - let left_padding = cols.saturating_sub(widths.0) / 2; - let first_row_coords = (rows.saturating_sub(self.ui_size) / 2).saturating_sub(1); - print_text_with_coordinates( - Text::new(title_text_1).color_range(2, ..), - left_padding, - first_row_coords, - None, - None, - ); - print_text_with_coordinates( - Text::new(title_text_2) - .color_range(0, ..10) - .color_range(2, 16..23) - .color_range(self.preset_color_index, 34..41), - left_padding, - first_row_coords + 2, - None, - None, - ); - print_text_with_coordinates( - Text::new(title_text_3), - left_padding, - first_row_coords + 4, - None, - None, - ); - print_text_with_coordinates( - Text::new(title_text_4), - left_padding, - first_row_coords + 5, - None, - None, - ); - } else { - let title_text_1 = "Hi there! Which do you prefer?"; - let title_text_2 = "Not sure? Press "; - let title_text_3 = "Can be changed later. Tips appear"; - let title_text_4 = "on screen - no need to remember"; - let left_padding = if cols >= widths.1 { - cols.saturating_sub(widths.1) / 2 - } else { - cols.saturating_sub(widths.2) / 2 - }; - let first_row_coords = (rows.saturating_sub(self.ui_size) / 2).saturating_sub(1); - print_text_with_coordinates( - Text::new(title_text_1).color_range(2, ..), - left_padding, - first_row_coords, - None, - None, - ); - print_text_with_coordinates( - Text::new(title_text_2) - .color_range(0, ..10) - .color_range(2, 16..23) - .color_range(self.preset_color_index, 40..49), - left_padding, - first_row_coords + 2, - None, - None, - ); - print_text_with_coordinates( - Text::new(title_text_3), - left_padding, - first_row_coords + 4, - None, - None, - ); - print_text_with_coordinates( - Text::new(title_text_4), - left_padding, - first_row_coords + 5, - None, - None, - ); - } - } - fn render_first_bulletin(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) { - let widths = self.main_screen_widths(primary_modifier_key_text); - let primary_modifier_key_text_len = primary_modifier_key_text.chars().count(); - let default_text = "1. Default"; - let (mut list_items, max_width) = if cols >= widths.0 { - let list_items = vec![ - NestedListItem::new(default_text).color_range(self.preset_color_index, ..), - NestedListItem::new("All modes available directly from the base mode, eg.:") - .indent(1), - NestedListItem::new(format!( - "{} p - to enter PANE mode", - primary_modifier_key_text - )) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 18, - ) - .indent(1), - NestedListItem::new(format!( - "{} t - to enter TAB mode", - primary_modifier_key_text - )) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 17, - ) - .indent(1), - ]; - let max_width = widths.0; - (list_items, max_width) - } else if cols >= widths.1 { - let list_items = vec![ - NestedListItem::new(default_text).color_range(self.preset_color_index, ..), - NestedListItem::new("Modes available directly, eg.:").indent(1), - NestedListItem::new(format!( - "{} p - to enter PANE mode", - primary_modifier_key_text - )) - .indent(1) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 18, - ), - NestedListItem::new(format!( - "{} t - to enter TAB mode", - primary_modifier_key_text - )) - .indent(1) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 17, - ), - ]; - let max_width = widths.1; - (list_items, max_width) - } else { - let list_items = vec![ - NestedListItem::new(default_text).color_range(self.preset_color_index, ..), - NestedListItem::new("Directly, eg.:").indent(1), - NestedListItem::new(format!("{} p - PANE mode", primary_modifier_key_text)) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 10, - ) - .indent(1), - NestedListItem::new(format!("{} t - TAB mode", primary_modifier_key_text)) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 9, - ) - .indent(1), - ]; - let max_width = widths.2; - (list_items, max_width) - }; - if self.selected_index == Some(0) { - list_items = list_items.drain(..).map(|i| i.selected()).collect(); - } - let left_padding = cols.saturating_sub(max_width) / 2; - let top_coordinates = if rows > 14 { - (rows.saturating_sub(self.ui_size) / 2) + 2 - } else { - (rows.saturating_sub(self.ui_size) / 2) + 1 - }; - print_nested_list_with_coordinates( - list_items, - left_padding, - top_coordinates, - Some(max_width), - None, - ); - } - fn render_second_bulletin(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) { - let unlock_first_text = "2. Unlock First (non-colliding)"; - let widths = self.main_screen_widths(primary_modifier_key_text); - let primary_modifier_key_text_len = primary_modifier_key_text.chars().count(); - let (mut list_items, max_width) = if cols >= widths.0 { - let list_items = vec![ - NestedListItem::new(unlock_first_text).color_range(self.preset_color_index, ..), - NestedListItem::new(format!( - "Single key modes available after unlocking with {} g, eg.:", - primary_modifier_key_text - )) - .indent(1), - NestedListItem::new(format!( - "{} g + p to enter PANE mode", - primary_modifier_key_text - )) - .indent(1) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.primary_leader_key_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 21, - ), - NestedListItem::new(format!( - "{} g + t to enter TAB mode", - primary_modifier_key_text - )) - .indent(1) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.primary_leader_key_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 20, - ), - ]; - let max_width = widths.0; - (list_items, max_width) - } else if cols >= widths.1 { - let list_items = vec![ - NestedListItem::new(unlock_first_text).color_range(self.preset_color_index, ..), - NestedListItem::new(format!( - "Single key modes after {} g, eg.:", - primary_modifier_key_text - )) - .indent(1), - NestedListItem::new(format!( - "{} g + p to enter PANE mode", - primary_modifier_key_text - )) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.primary_leader_key_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 21, - ) - .indent(1), - NestedListItem::new(format!( - "{} g + t to enter TAB mode", - primary_modifier_key_text - )) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.primary_leader_key_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 20, - ) - .indent(1), - ]; - let max_width = widths.1; - (list_items, max_width) - } else { - let list_items = vec![ - NestedListItem::new("2. Unlock First").color_range(self.preset_color_index, ..), - NestedListItem::new(format!( - "{} g + single key, eg.:", - primary_modifier_key_text - )) - .indent(1), - NestedListItem::new(format!("{} g + p PANE mode", primary_modifier_key_text)) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.primary_leader_key_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 7..primary_modifier_key_text_len + 11, - ) - .indent(1), - NestedListItem::new(format!("{} g + t TAB mode", primary_modifier_key_text)) - .color_range( - self.primary_leader_key_color_index, - ..primary_modifier_key_text_len + 3, - ) - .color_range( - self.primary_leader_key_color_index, - primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, - ) - .color_range( - self.mode_color_index, - primary_modifier_key_text_len + 7..primary_modifier_key_text_len + 10, - ) - .indent(1), - ]; - let max_width = widths.2; - (list_items, max_width) - }; - if self.selected_index == Some(1) { - list_items = list_items.drain(..).map(|i| i.selected()).collect(); - } - let left_padding = cols.saturating_sub(max_width) / 2; - let top_coordinates = if rows > 14 { - (rows.saturating_sub(self.ui_size) / 2) + 7 - } else { - (rows.saturating_sub(self.ui_size) / 2) + 5 - }; - print_nested_list_with_coordinates( - list_items, - left_padding, - top_coordinates, - Some(max_width), - None, - ); - } - fn render_leader_keys_indication( - &self, - rows: usize, - cols: usize, - primary_modifier_key_text: &str, - secondary_modifier_key_text: &str, - ) { - let widths = self.main_screen_widths(primary_modifier_key_text); - let primary_modifier_key_text_len = primary_modifier_key_text.chars().count(); - let secondary_modifier_key_text_len = secondary_modifier_key_text.chars().count(); - let top_coordinates = if rows > 14 { - (rows.saturating_sub(self.ui_size) / 2) + 12 - } else { - (rows.saturating_sub(self.ui_size) / 2) + 9 - }; - - if cols >= widths.0 { - let leader_key_text = format!( - "Leader keys: {} - modes, {} - quicknav and shortcuts", - primary_modifier_key_text, secondary_modifier_key_text - ); - let left_padding = cols.saturating_sub(widths.0) / 2; - print_text_with_coordinates( - Text::new(leader_key_text) - .color_range(2, ..12) - .color_range( - self.primary_leader_key_color_index, - 13..primary_modifier_key_text_len + 14, - ) - .color_range( - self.secondary_leader_key_color_index, - primary_modifier_key_text_len + 23 - ..primary_modifier_key_text_len + 23 + secondary_modifier_key_text_len, - ), - left_padding, - top_coordinates, - None, - None, - ) - } else { - let leader_key_text = format!( - "Leaders: {}, {}", - primary_modifier_key_text, secondary_modifier_key_text - ); - let left_padding = if cols >= widths.1 { - cols.saturating_sub(widths.1) / 2 - } else { - cols.saturating_sub(widths.2) / 2 - }; - print_text_with_coordinates( - Text::new(leader_key_text) - .color_range(2, ..8) - .color_range( - self.primary_leader_key_color_index, - 9..primary_modifier_key_text_len + 10, - ) - .color_range( - self.secondary_leader_key_color_index, - primary_modifier_key_text_len + 11 - ..primary_modifier_key_text_len + 12 + secondary_modifier_key_text_len, - ), - left_padding, - top_coordinates, - None, - None, - ) - }; - } - fn render_info_line(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) { - let widths = self.main_screen_widths(primary_modifier_key_text); - let top_coordinates = if rows > 14 { - (rows.saturating_sub(self.ui_size) / 2) + 14 - } else { - (rows.saturating_sub(self.ui_size) / 2) + 10 - }; - let left_padding = if cols >= widths.0 { - cols.saturating_sub(widths.0) / 2 - } else if cols >= widths.1 { - cols.saturating_sub(widths.1) / 2 - } else { - cols.saturating_sub(widths.2) / 2 - }; - if let Some(notification) = &self.notification { - print_text_with_coordinates( - Text::new(notification).color_range(3, ..), - left_padding, - top_coordinates, - None, - None, - ); - } else if let Some(warning_text) = self.warning_text(cols) { - print_text_with_coordinates( - Text::new(warning_text).color_range(3, ..), - left_padding, - top_coordinates, - None, - None, - ); - } - } - fn render_help_text_main(&self, rows: usize, cols: usize) { - let full_help_text = "Help: <↓↑> - navigate, - apply, - apply & save, - leaders, - close"; - let short_help_text = "Help: <↓↑> / / / / "; - if cols >= full_help_text.chars().count() { - print_text_with_coordinates( - Text::new(full_help_text) - .color_range(2, 6..10) - .color_range(2, 23..30) - .color_range(2, 40..47) - .color_range(2, 64..67) - .color_range(2, 79..84), - 0, - rows, - None, - None, - ); - } else { - print_text_with_coordinates( - Text::new(short_help_text) - .color_range(2, 6..10) - .color_range(2, 13..20) - .color_range(2, 23..30) - .color_range(2, 33..36) - .color_range(2, 39..44), - 0, - rows, - None, - None, - ); - } - } - fn render_help_text_setup_wizard(&self, rows: usize, cols: usize) { - let full_help_text = - "Help: <↓↑> - navigate, - apply & save, - change leaders, - close"; - let short_help_text = "Help: <↓↑> / / / "; - if cols >= full_help_text.chars().count() { - print_text_with_coordinates( - Text::new(full_help_text) - .color_range(2, 6..10) - .color_range(2, 23..30) - .color_range(2, 47..50) - .color_range(2, 69..74), - 0, - rows, - None, - None, - ); - } else { - print_text_with_coordinates( - Text::new(short_help_text) - .color_range(2, 6..10) - .color_range(2, 13..20) - .color_range(2, 23..26) - .color_range(2, 29..34), - 0, - rows, - None, - None, - ); - } - } - fn render_help_text_remapping(&self, rows: usize, cols: usize) { - let widths = self.remapping_screen_widths(); - if cols >= widths.0 { - let help_text = "Help: - when done"; - print_text_with_coordinates( - Text::new(help_text).color_range(2, 6..13), - 0, - rows, - None, - None, - ); - } else { - let help_text = "Help: / <←↓↑→> / "; - print_text_with_coordinates( - Text::new(help_text) - .color_range(2, 6..13) - .color_range(2, 16..22) - .color_range(2, 25..32), - 0, - rows, - None, - None, - ); - } - } - fn primary_modifier_text(&self) -> String { - if self.primary_modifier.is_empty() { - "".to_owned() - } else { - self.primary_modifier - .iter() - .map(|m| m.to_string()) - .collect::>() - .join("-") - } - } - fn secondary_modifier_text(&self) -> String { - if self.secondary_modifier.is_empty() { - "".to_owned() - } else { - self.secondary_modifier - .iter() - .map(|m| m.to_string()) - .collect::>() - .join("-") - } - } - fn main_screen_widths(&self, primary_modifier_text: &str) -> (usize, usize, usize) { - let primary_modifier_key_text_len = primary_modifier_text.chars().count(); - let full_width = 61 + primary_modifier_key_text_len; - let mid_width = 36 + primary_modifier_key_text_len; - let min_width = 26 + primary_modifier_key_text_len; - (full_width, mid_width, min_width) - } - fn remapping_screen_widths(&self) -> (usize, usize, usize) { - let full_width = 62; - let mid_width = 42; - let min_width = 30; - (full_width, mid_width, min_width) - } - fn render_main_screen(&mut self, rows: usize, cols: usize) { - let primary_modifier_key_text = self.primary_modifier_text(); - let secondary_modifier_key_text = self.secondary_modifier_text(); - self.render_override_title(rows, cols, &primary_modifier_key_text); - self.render_first_bulletin(rows, cols, &primary_modifier_key_text); - self.render_second_bulletin(rows, cols, &primary_modifier_key_text); - self.render_leader_keys_indication( - rows, - cols, - &primary_modifier_key_text, - &secondary_modifier_key_text, - ); - self.render_info_line(rows, cols, &primary_modifier_key_text); - self.render_help_text_main(rows, cols); - } - fn render_setup_wizard_screen(&mut self, rows: usize, cols: usize) { - let primary_modifier_key_text = self.primary_modifier_text(); - let secondary_modifier_key_text = self.secondary_modifier_text(); - self.render_setup_wizard_title(rows, cols, &primary_modifier_key_text); - self.render_first_bulletin(rows + 8, cols, &primary_modifier_key_text); - self.render_second_bulletin(rows + 8, cols, &primary_modifier_key_text); - self.render_leader_keys_indication( - rows + 8, - cols, - &primary_modifier_key_text, - &secondary_modifier_key_text, - ); - self.render_info_line(rows + 8, cols, &primary_modifier_key_text); - self.render_help_text_setup_wizard(rows + 8, cols); - } - fn warning_text(&self, max_width: usize) -> Option { - if self.needs_kitty_support() { - // TODO: some widget to test support by detecting pressed keys - 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 disabled.")) - } - } 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) - } - fn reconfigure(&self, selected: usize, write_to_disk: bool) { - if selected == 0 { - // TODO: these should be part of a "transaction" when they are - // implemented - reconfigure( - default_keybinds( - self.primary_modifier - .iter() - .map(|m| m.to_string()) - .collect::>() - .join(" "), - self.secondary_modifier - .iter() - .map(|m| m.to_string()) - .collect::>() - .join(" "), - ), - write_to_disk, - ); - switch_to_input_mode(&InputMode::Normal); - } else if selected == 1 { - // TODO: these should be part of a "transaction" when they are - // implemented - reconfigure( - unlock_first_keybinds( - self.primary_modifier - .iter() - .map(|m| m.to_string()) - .collect::>() - .join(" "), - self.secondary_modifier - .iter() - .map(|m| m.to_string()) - .collect::>() - .join(" "), - ), - write_to_disk, - ); - switch_to_input_mode(&InputMode::Locked); + if let Some(mode_info) = &self.latest_mode_info { + self.current_screen.update_mode_info(mode_info.clone()); } } } - -fn unlock_first_keybinds(primary_modifier: String, secondary_modifier: String) -> String { - format!( - r#" -default_mode "locked" -keybinds clear-defaults=true {{ - normal {{ - }} - locked {{ - bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} - }} - resize {{ - bind "r" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ Resize "Increase Left"; }} - bind "j" "Down" {{ Resize "Increase Down"; }} - bind "k" "Up" {{ Resize "Increase Up"; }} - bind "l" "Right" {{ Resize "Increase Right"; }} - bind "H" {{ Resize "Decrease Left"; }} - bind "J" {{ Resize "Decrease Down"; }} - bind "K" {{ Resize "Decrease Up"; }} - bind "L" {{ Resize "Decrease Right"; }} - bind "=" "+" {{ Resize "Increase"; }} - bind "-" {{ Resize "Decrease"; }} - }} - pane {{ - bind "p" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ MoveFocus "Left"; }} - bind "l" "Right" {{ MoveFocus "Right"; }} - bind "j" "Down" {{ MoveFocus "Down"; }} - bind "k" "Up" {{ MoveFocus "Up"; }} - bind "Tab" {{ SwitchFocus; }} - bind "n" {{ NewPane; SwitchToMode "Locked"; }} - bind "d" {{ NewPane "Down"; SwitchToMode "Locked"; }} - bind "r" {{ NewPane "Right"; SwitchToMode "Locked"; }} - bind "x" {{ CloseFocus; SwitchToMode "Locked"; }} - bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Locked"; }} - bind "z" {{ TogglePaneFrames; SwitchToMode "Locked"; }} - bind "w" {{ ToggleFloatingPanes; SwitchToMode "Locked"; }} - bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Locked"; }} - bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} - }} - move {{ - bind "m" {{ SwitchToMode "Normal"; }} - bind "n" "Tab" {{ MovePane; }} - bind "p" {{ MovePaneBackwards; }} - bind "h" "Left" {{ MovePane "Left"; }} - bind "j" "Down" {{ MovePane "Down"; }} - bind "k" "Up" {{ MovePane "Up"; }} - bind "l" "Right" {{ MovePane "Right"; }} - }} - tab {{ - bind "t" {{ SwitchToMode "Normal"; }} - bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} - bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} - bind "l" "Right" "Down" "j" {{ GoToNextTab; }} - bind "n" {{ NewTab; SwitchToMode "Locked"; }} - bind "x" {{ CloseTab; SwitchToMode "Locked"; }} - bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Locked"; }} - bind "b" {{ BreakPane; SwitchToMode "Locked"; }} - bind "]" {{ BreakPaneRight; SwitchToMode "Locked"; }} - bind "[" {{ BreakPaneLeft; SwitchToMode "Locked"; }} - bind "1" {{ GoToTab 1; SwitchToMode "Locked"; }} - bind "2" {{ GoToTab 2; SwitchToMode "Locked"; }} - bind "3" {{ GoToTab 3; SwitchToMode "Locked"; }} - bind "4" {{ GoToTab 4; SwitchToMode "Locked"; }} - bind "5" {{ GoToTab 5; SwitchToMode "Locked"; }} - bind "6" {{ GoToTab 6; SwitchToMode "Locked"; }} - bind "7" {{ GoToTab 7; SwitchToMode "Locked"; }} - bind "8" {{ GoToTab 8; SwitchToMode "Locked"; }} - bind "9" {{ GoToTab 9; SwitchToMode "Locked"; }} - bind "Tab" {{ ToggleTab; }} - }} - scroll {{ - bind "s" {{ SwitchToMode "Normal"; }} - bind "e" {{ EditScrollback; SwitchToMode "Locked"; }} - bind "f" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Locked"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - }} - search {{ - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Locked"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - bind "n" {{ Search "down"; }} - bind "p" {{ Search "up"; }} - bind "c" {{ SearchToggleOption "CaseSensitivity"; }} - bind "w" {{ SearchToggleOption "Wrap"; }} - bind "o" {{ SearchToggleOption "WholeWord"; }} - }} - entersearch {{ - bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} - bind "Enter" {{ SwitchToMode "Search"; }} - }} - renametab {{ - bind "Ctrl c" "Enter" {{ SwitchToMode "Locked"; }} - bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} - }} - renamepane {{ - bind "Ctrl c" "Enter" {{ SwitchToMode "Locked"; }} - bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} - }} - session {{ - bind "o" {{ SwitchToMode "Normal"; }} - bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} - bind "d" {{ Detach; }} - bind "w" {{ - LaunchOrFocusPlugin "session-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Locked" - }} - bind "c" {{ - LaunchOrFocusPlugin "configuration" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Locked" - }} - bind "p" {{ - LaunchOrFocusPlugin "plugin-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Locked" - }} - }} - shared_except "locked" "renametab" "renamepane" {{ - bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} - bind "{primary_modifier} q" {{ Quit; }} - }} - shared_except "renamepane" "renametab" "entersearch" "locked" {{ - bind "esc" {{ SwitchToMode "locked"; }} - }} - shared_among "normal" "locked" {{ - bind "{secondary_modifier} n" {{ NewPane; }} - bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} - bind "{secondary_modifier} i" {{ MoveTab "Left"; }} - bind "{secondary_modifier} o" {{ MoveTab "Right"; }} - bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} - bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} - bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} - bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} - bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} - bind "{secondary_modifier} -" {{ Resize "Decrease"; }} - bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} - bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - }} - shared_except "locked" "renametab" "renamepane" {{ - bind "Enter" {{ SwitchToMode "Locked"; }} - }} - shared_except "pane" "locked" "renametab" "renamepane" "entersearch" {{ - bind "p" {{ SwitchToMode "Pane"; }} - }} - shared_except "resize" "locked" "renametab" "renamepane" "entersearch" {{ - bind "r" {{ SwitchToMode "Resize"; }} - }} - shared_except "scroll" "locked" "renametab" "renamepane" "entersearch" {{ - bind "s" {{ SwitchToMode "Scroll"; }} - }} - shared_except "session" "locked" "renametab" "renamepane" "entersearch" {{ - bind "o" {{ SwitchToMode "Session"; }} - }} - shared_except "tab" "locked" "renametab" "renamepane" "entersearch" {{ - bind "t" {{ SwitchToMode "Tab"; }} - }} - shared_except "move" "locked" "renametab" "renamepane" "entersearch" {{ - bind "m" {{ SwitchToMode "Move"; }} - }} -}}"# - ) -} - -fn default_keybinds(primary_modifier: String, secondary_modifier: String) -> String { - if primary_modifier.is_empty() && secondary_modifier.is_empty() { - return default_keybinds_no_modifiers(); - } else if primary_modifier == secondary_modifier { - return non_colliding_default_keybinds(primary_modifier, secondary_modifier); - } else if primary_modifier.is_empty() { - return default_keybinds_no_primary_modifier(secondary_modifier); - } else if secondary_modifier.is_empty() { - return default_keybinds_no_secondary_modifier(primary_modifier); - } - format!( - r#" -default_mode "normal" -keybinds clear-defaults=true {{ - normal {{}} - locked {{ - bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} - }} - resize {{ - bind "{primary_modifier} n" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ Resize "Increase Left"; }} - bind "j" "Down" {{ Resize "Increase Down"; }} - bind "k" "Up" {{ Resize "Increase Up"; }} - bind "l" "Right" {{ Resize "Increase Right"; }} - bind "H" {{ Resize "Decrease Left"; }} - bind "J" {{ Resize "Decrease Down"; }} - bind "K" {{ Resize "Decrease Up"; }} - bind "L" {{ Resize "Decrease Right"; }} - bind "=" "+" {{ Resize "Increase"; }} - bind "-" {{ Resize "Decrease"; }} - }} - pane {{ - bind "{primary_modifier} p" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ MoveFocus "Left"; }} - bind "l" "Right" {{ MoveFocus "Right"; }} - bind "j" "Down" {{ MoveFocus "Down"; }} - bind "k" "Up" {{ MoveFocus "Up"; }} - bind "p" {{ SwitchFocus; }} - bind "n" {{ NewPane; SwitchToMode "Normal"; }} - bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} - bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} - bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} - bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} - }} - move {{ - bind "{primary_modifier} h" {{ SwitchToMode "Normal"; }} - bind "n" "Tab" {{ MovePane; }} - bind "p" {{ MovePaneBackwards; }} - bind "h" "Left" {{ MovePane "Left"; }} - bind "j" "Down" {{ MovePane "Down"; }} - bind "k" "Up" {{ MovePane "Up"; }} - bind "l" "Right" {{ MovePane "Right"; }} - }} - tab {{ - bind "{primary_modifier} t" {{ SwitchToMode "Normal"; }} - bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} - bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} - bind "l" "Right" "Down" "j" {{ GoToNextTab; }} - bind "n" {{ NewTab; SwitchToMode "Normal"; }} - bind "x" {{ CloseTab; SwitchToMode "Normal"; }} - bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} - bind "b" {{ BreakPane; SwitchToMode "Normal"; }} - bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} - bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} - bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} - bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} - bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} - bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} - bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} - bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} - bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} - bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} - bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} - bind "Tab" {{ ToggleTab; }} - }} - scroll {{ - bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} - bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} - bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - }} - search {{ - bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - bind "n" {{ Search "down"; }} - bind "p" {{ Search "up"; }} - bind "c" {{ SearchToggleOption "CaseSensitivity"; }} - bind "w" {{ SearchToggleOption "Wrap"; }} - bind "o" {{ SearchToggleOption "WholeWord"; }} - }} - entersearch {{ - bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} - bind "Enter" {{ SwitchToMode "Search"; }} - }} - renametab {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} - }} - renamepane {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} - }} - session {{ - bind "{primary_modifier} o" {{ SwitchToMode "Normal"; }} - bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} - bind "d" {{ Detach; }} - bind "w" {{ - LaunchOrFocusPlugin "session-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "c" {{ - LaunchOrFocusPlugin "configuration" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "p" {{ - LaunchOrFocusPlugin "plugin-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - }} - tmux {{ - bind "[" {{ SwitchToMode "Scroll"; }} - bind "{primary_modifier} b" {{ Write 2; SwitchToMode "Normal"; }} - bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "c" {{ NewTab; SwitchToMode "Normal"; }} - bind "," {{ SwitchToMode "RenameTab"; }} - bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} - bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} - bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "o" {{ FocusNextPane; }} - bind "d" {{ Detach; }} - bind "Space" {{ NextSwapLayout; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - }} - shared_except "locked" {{ - bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} - bind "{primary_modifier} q" {{ Quit; }} - bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} - bind "{secondary_modifier} n" {{ NewPane; }} - bind "{secondary_modifier} i" {{ MoveTab "Left"; }} - bind "{secondary_modifier} o" {{ MoveTab "Right"; }} - bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} - bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} - bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} - bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} - bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} - bind "{secondary_modifier} -" {{ Resize "Decrease"; }} - bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} - bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - }} - shared_except "normal" "locked" {{ - bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} - }} - shared_except "pane" "locked" {{ - bind "{primary_modifier} p" {{ SwitchToMode "Pane"; }} - }} - shared_except "resize" "locked" {{ - bind "{primary_modifier} n" {{ SwitchToMode "Resize"; }} - }} - shared_except "scroll" "locked" {{ - bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} - }} - shared_except "session" "locked" {{ - bind "{primary_modifier} o" {{ SwitchToMode "Session"; }} - }} - shared_except "tab" "locked" {{ - bind "{primary_modifier} t" {{ SwitchToMode "Tab"; }} - }} - shared_except "move" "locked" {{ - bind "{primary_modifier} h" {{ SwitchToMode "Move"; }} - }} - shared_except "tmux" "locked" {{ - bind "{primary_modifier} b" {{ SwitchToMode "Tmux"; }} - }} -}} -"# - ) -} - -fn default_keybinds_no_primary_modifier(secondary_modifier: String) -> String { - format!( - r#" -default_mode "normal" -keybinds clear-defaults=true {{ - normal {{}} - locked {{}} - resize {{ - bind "h" "Left" {{ Resize "Increase Left"; }} - bind "j" "Down" {{ Resize "Increase Down"; }} - bind "k" "Up" {{ Resize "Increase Up"; }} - bind "l" "Right" {{ Resize "Increase Right"; }} - bind "H" {{ Resize "Decrease Left"; }} - bind "J" {{ Resize "Decrease Down"; }} - bind "K" {{ Resize "Decrease Up"; }} - bind "L" {{ Resize "Decrease Right"; }} - bind "=" "+" {{ Resize "Increase"; }} - bind "-" {{ Resize "Decrease"; }} - }} - pane {{ - bind "h" "Left" {{ MoveFocus "Left"; }} - bind "l" "Right" {{ MoveFocus "Right"; }} - bind "j" "Down" {{ MoveFocus "Down"; }} - bind "k" "Up" {{ MoveFocus "Up"; }} - bind "p" {{ SwitchFocus; }} - bind "n" {{ NewPane; SwitchToMode "Normal"; }} - bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} - bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} - bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} - bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} - }} - move {{ - bind "n" "Tab" {{ MovePane; }} - bind "p" {{ MovePaneBackwards; }} - bind "h" "Left" {{ MovePane "Left"; }} - bind "j" "Down" {{ MovePane "Down"; }} - bind "k" "Up" {{ MovePane "Up"; }} - bind "l" "Right" {{ MovePane "Right"; }} - }} - tab {{ - bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} - bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} - bind "l" "Right" "Down" "j" {{ GoToNextTab; }} - bind "n" {{ NewTab; SwitchToMode "Normal"; }} - bind "x" {{ CloseTab; SwitchToMode "Normal"; }} - bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} - bind "b" {{ BreakPane; SwitchToMode "Normal"; }} - bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} - bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} - bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} - bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} - bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} - bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} - bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} - bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} - bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} - bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} - bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} - bind "Tab" {{ ToggleTab; }} - }} - scroll {{ - bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} - bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - }} - search {{ - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - bind "n" {{ Search "down"; }} - bind "p" {{ Search "up"; }} - bind "c" {{ SearchToggleOption "CaseSensitivity"; }} - bind "w" {{ SearchToggleOption "Wrap"; }} - bind "o" {{ SearchToggleOption "WholeWord"; }} - }} - entersearch {{ - bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} - bind "Enter" {{ SwitchToMode "Search"; }} - }} - renametab {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} - }} - renamepane {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} - }} - session {{ - bind "d" {{ Detach; }} - bind "w" {{ - LaunchOrFocusPlugin "session-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "c" {{ - LaunchOrFocusPlugin "configuration" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "p" {{ - LaunchOrFocusPlugin "plugin-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - }} - tmux {{ - bind "[" {{ SwitchToMode "Scroll"; }} - bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "c" {{ NewTab; SwitchToMode "Normal"; }} - bind "," {{ SwitchToMode "RenameTab"; }} - bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} - bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} - bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "o" {{ FocusNextPane; }} - bind "d" {{ Detach; }} - bind "Space" {{ NextSwapLayout; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - }} - shared_except "locked" {{ - bind "{secondary_modifier} n" {{ NewPane; }} - bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} - bind "{secondary_modifier} i" {{ MoveTab "Left"; }} - bind "{secondary_modifier} o" {{ MoveTab "Right"; }} - bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} - bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} - bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} - bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} - bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} - bind "{secondary_modifier} -" {{ Resize "Decrease"; }} - bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} - bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - }} - shared_except "normal" "locked" {{ - bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} - }} -}} -"# - ) -} - -fn default_keybinds_no_secondary_modifier(primary_modifier: String) -> String { - format!( - r#" -default_mode "normal" -keybinds clear-defaults=true {{ - normal {{}} - locked {{ - bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} - }} - resize {{ - bind "{primary_modifier} n" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ Resize "Increase Left"; }} - bind "j" "Down" {{ Resize "Increase Down"; }} - bind "k" "Up" {{ Resize "Increase Up"; }} - bind "l" "Right" {{ Resize "Increase Right"; }} - bind "H" {{ Resize "Decrease Left"; }} - bind "J" {{ Resize "Decrease Down"; }} - bind "K" {{ Resize "Decrease Up"; }} - bind "L" {{ Resize "Decrease Right"; }} - bind "=" "+" {{ Resize "Increase"; }} - bind "-" {{ Resize "Decrease"; }} - }} - pane {{ - bind "{primary_modifier} p" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ MoveFocus "Left"; }} - bind "l" "Right" {{ MoveFocus "Right"; }} - bind "j" "Down" {{ MoveFocus "Down"; }} - bind "k" "Up" {{ MoveFocus "Up"; }} - bind "p" {{ SwitchFocus; }} - bind "n" {{ NewPane; SwitchToMode "Normal"; }} - bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} - bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} - bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} - bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} - }} - move {{ - bind "{primary_modifier} h" {{ SwitchToMode "Normal"; }} - bind "n" "Tab" {{ MovePane; }} - bind "p" {{ MovePaneBackwards; }} - bind "h" "Left" {{ MovePane "Left"; }} - bind "j" "Down" {{ MovePane "Down"; }} - bind "k" "Up" {{ MovePane "Up"; }} - bind "l" "Right" {{ MovePane "Right"; }} - }} - tab {{ - bind "{primary_modifier} t" {{ SwitchToMode "Normal"; }} - bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} - bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} - bind "l" "Right" "Down" "j" {{ GoToNextTab; }} - bind "n" {{ NewTab; SwitchToMode "Normal"; }} - bind "x" {{ CloseTab; SwitchToMode "Normal"; }} - bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} - bind "b" {{ BreakPane; SwitchToMode "Normal"; }} - bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} - bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} - bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} - bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} - bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} - bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} - bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} - bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} - bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} - bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} - bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} - bind "Tab" {{ ToggleTab; }} - }} - scroll {{ - bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} - bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} - bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - }} - search {{ - bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - bind "n" {{ Search "down"; }} - bind "p" {{ Search "up"; }} - bind "c" {{ SearchToggleOption "CaseSensitivity"; }} - bind "w" {{ SearchToggleOption "Wrap"; }} - bind "o" {{ SearchToggleOption "WholeWord"; }} - }} - entersearch {{ - bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} - bind "Enter" {{ SwitchToMode "Search"; }} - }} - renametab {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} - }} - renamepane {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} - }} - session {{ - bind "{primary_modifier} o" {{ SwitchToMode "Normal"; }} - bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} - bind "d" {{ Detach; }} - bind "w" {{ - LaunchOrFocusPlugin "session-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "c" {{ - LaunchOrFocusPlugin "configuration" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "p" {{ - LaunchOrFocusPlugin "plugin-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - }} - tmux {{ - bind "[" {{ SwitchToMode "Scroll"; }} - bind "{primary_modifier} b" {{ Write 2; SwitchToMode "Normal"; }} - bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "c" {{ NewTab; SwitchToMode "Normal"; }} - bind "," {{ SwitchToMode "RenameTab"; }} - bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} - bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} - bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "o" {{ FocusNextPane; }} - bind "d" {{ Detach; }} - bind "Space" {{ NextSwapLayout; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - }} - shared_except "locked" {{ - bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} - bind "{primary_modifier} q" {{ Quit; }} - }} - shared_except "normal" "locked" {{ - bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} - }} - shared_except "pane" "locked" {{ - bind "{primary_modifier} p" {{ SwitchToMode "Pane"; }} - }} - shared_except "resize" "locked" {{ - bind "{primary_modifier} n" {{ SwitchToMode "Resize"; }} - }} - shared_except "scroll" "locked" {{ - bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} - }} - shared_except "session" "locked" {{ - bind "{primary_modifier} o" {{ SwitchToMode "Session"; }} - }} - shared_except "tab" "locked" {{ - bind "{primary_modifier} t" {{ SwitchToMode "Tab"; }} - }} - shared_except "move" "locked" {{ - bind "{primary_modifier} h" {{ SwitchToMode "Move"; }} - }} - shared_except "tmux" "locked" {{ - bind "{primary_modifier} b" {{ SwitchToMode "Tmux"; }} - }} -}} -"# - ) -} - -fn default_keybinds_no_modifiers() -> String { - format!( - r#" -default_mode "normal" -keybinds clear-defaults=true {{ - normal {{}} - locked {{}} - resize {{ - bind "h" "Left" {{ Resize "Increase Left"; }} - bind "j" "Down" {{ Resize "Increase Down"; }} - bind "k" "Up" {{ Resize "Increase Up"; }} - bind "l" "Right" {{ Resize "Increase Right"; }} - bind "H" {{ Resize "Decrease Left"; }} - bind "J" {{ Resize "Decrease Down"; }} - bind "K" {{ Resize "Decrease Up"; }} - bind "L" {{ Resize "Decrease Right"; }} - bind "=" "+" {{ Resize "Increase"; }} - bind "-" {{ Resize "Decrease"; }} - }} - pane {{ - bind "h" "Left" {{ MoveFocus "Left"; }} - bind "l" "Right" {{ MoveFocus "Right"; }} - bind "j" "Down" {{ MoveFocus "Down"; }} - bind "k" "Up" {{ MoveFocus "Up"; }} - bind "p" {{ SwitchFocus; }} - bind "n" {{ NewPane; SwitchToMode "Normal"; }} - bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} - bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} - bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} - bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} - }} - move {{ - bind "n" "Tab" {{ MovePane; }} - bind "p" {{ MovePaneBackwards; }} - bind "h" "Left" {{ MovePane "Left"; }} - bind "j" "Down" {{ MovePane "Down"; }} - bind "k" "Up" {{ MovePane "Up"; }} - bind "l" "Right" {{ MovePane "Right"; }} - }} - tab {{ - bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} - bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} - bind "l" "Right" "Down" "j" {{ GoToNextTab; }} - bind "n" {{ NewTab; SwitchToMode "Normal"; }} - bind "x" {{ CloseTab; SwitchToMode "Normal"; }} - bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} - bind "b" {{ BreakPane; SwitchToMode "Normal"; }} - bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} - bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} - bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} - bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} - bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} - bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} - bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} - bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} - bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} - bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} - bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} - bind "Tab" {{ ToggleTab; }} - }} - scroll {{ - bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} - bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - }} - search {{ - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - bind "n" {{ Search "down"; }} - bind "p" {{ Search "up"; }} - bind "c" {{ SearchToggleOption "CaseSensitivity"; }} - bind "w" {{ SearchToggleOption "Wrap"; }} - bind "o" {{ SearchToggleOption "WholeWord"; }} - }} - entersearch {{ - bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} - bind "Enter" {{ SwitchToMode "Search"; }} - }} - renametab {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} - }} - renamepane {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} - }} - session {{ - bind "d" {{ Detach; }} - bind "w" {{ - LaunchOrFocusPlugin "session-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "c" {{ - LaunchOrFocusPlugin "configuration" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "p" {{ - LaunchOrFocusPlugin "plugin-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - }} - tmux {{ - bind "[" {{ SwitchToMode "Scroll"; }} - bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "c" {{ NewTab; SwitchToMode "Normal"; }} - bind "," {{ SwitchToMode "RenameTab"; }} - bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} - bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} - bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "o" {{ FocusNextPane; }} - bind "d" {{ Detach; }} - bind "Space" {{ NextSwapLayout; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - }} - shared_except "normal" "locked" {{ - bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} - }} -}} -"# - ) -} - -fn non_colliding_default_keybinds(primary_modifier: String, secondary_modifier: String) -> String { - format!( - r#" -default_mode "normal" -keybinds clear-defaults=true {{ - normal {{}} - locked {{ - bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} - }} - resize {{ - bind "{primary_modifier} r" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ Resize "Increase Left"; }} - bind "j" "Down" {{ Resize "Increase Down"; }} - bind "k" "Up" {{ Resize "Increase Up"; }} - bind "l" "Right" {{ Resize "Increase Right"; }} - bind "H" {{ Resize "Decrease Left"; }} - bind "J" {{ Resize "Decrease Down"; }} - bind "K" {{ Resize "Decrease Up"; }} - bind "L" {{ Resize "Decrease Right"; }} - bind "=" "+" {{ Resize "Increase"; }} - bind "-" {{ Resize "Decrease"; }} - }} - pane {{ - bind "{primary_modifier} p" {{ SwitchToMode "Normal"; }} - bind "h" "Left" {{ MoveFocus "Left"; }} - bind "l" "Right" {{ MoveFocus "Right"; }} - bind "j" "Down" {{ MoveFocus "Down"; }} - bind "k" "Up" {{ MoveFocus "Up"; }} - bind "p" {{ SwitchFocus; }} - bind "n" {{ NewPane; SwitchToMode "Normal"; }} - bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} - bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} - bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} - bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} - }} - move {{ - bind "{primary_modifier} m" {{ SwitchToMode "Normal"; }} - bind "n" "Tab" {{ MovePane; }} - bind "p" {{ MovePaneBackwards; }} - bind "h" "Left" {{ MovePane "Left"; }} - bind "j" "Down" {{ MovePane "Down"; }} - bind "k" "Up" {{ MovePane "Up"; }} - bind "l" "Right" {{ MovePane "Right"; }} - }} - tab {{ - bind "{primary_modifier} t" {{ SwitchToMode "Normal"; }} - bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} - bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} - bind "l" "Right" "Down" "j" {{ GoToNextTab; }} - bind "n" {{ NewTab; SwitchToMode "Normal"; }} - bind "x" {{ CloseTab; SwitchToMode "Normal"; }} - bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} - bind "b" {{ BreakPane; SwitchToMode "Normal"; }} - bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} - bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} - bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} - bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} - bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} - bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} - bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} - bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} - bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} - bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} - bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} - bind "Tab" {{ ToggleTab; }} - }} - scroll {{ - bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} - bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} - bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - }} - search {{ - bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} - bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} - bind "j" "Down" {{ ScrollDown; }} - bind "k" "Up" {{ ScrollUp; }} - bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} - bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} - bind "d" {{ HalfPageScrollDown; }} - bind "u" {{ HalfPageScrollUp; }} - bind "n" {{ Search "down"; }} - bind "p" {{ Search "up"; }} - bind "c" {{ SearchToggleOption "CaseSensitivity"; }} - bind "w" {{ SearchToggleOption "Wrap"; }} - bind "o" {{ SearchToggleOption "WholeWord"; }} - }} - entersearch {{ - bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} - bind "Enter" {{ SwitchToMode "Search"; }} - }} - renametab {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} - }} - renamepane {{ - bind "Ctrl c" {{ SwitchToMode "Normal"; }} - bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} - }} - session {{ - bind "{primary_modifier} o" {{ SwitchToMode "Normal"; }} - bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} - bind "d" {{ Detach; }} - bind "w" {{ - LaunchOrFocusPlugin "session-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "c" {{ - LaunchOrFocusPlugin "configuration" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - bind "p" {{ - LaunchOrFocusPlugin "plugin-manager" {{ - floating true - move_to_focused_tab true - }}; - SwitchToMode "Normal" - }} - }} - tmux {{ - bind "[" {{ SwitchToMode "Scroll"; }} - bind "{primary_modifier} b" {{ Write 2; SwitchToMode "Normal"; }} - bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} - bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} - bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} - bind "c" {{ NewTab; SwitchToMode "Normal"; }} - bind "," {{ SwitchToMode "RenameTab"; }} - bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} - bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} - bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} - bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} - bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} - bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} - bind "o" {{ FocusNextPane; }} - bind "d" {{ Detach; }} - bind "Space" {{ NextSwapLayout; }} - bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} - }} - shared_except "locked" {{ - bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} - bind "{primary_modifier} q" {{ Quit; }} - bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} - bind "{secondary_modifier} n" {{ NewPane; }} - bind "{secondary_modifier} i" {{ MoveTab "Left"; }} - bind "{secondary_modifier} o" {{ MoveTab "Right"; }} - bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} - bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} - bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} - bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} - bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} - bind "{secondary_modifier} -" {{ Resize "Decrease"; }} - bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} - bind "{secondary_modifier} ]" {{ NextSwapLayout; }} - }} - shared_except "normal" "locked" {{ - bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} - }} - shared_except "pane" "locked" {{ - bind "{primary_modifier} p" {{ SwitchToMode "Pane"; }} - }} - shared_except "resize" "locked" {{ - bind "{primary_modifier} r" {{ SwitchToMode "Resize"; }} - }} - shared_except "scroll" "locked" {{ - bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} - }} - shared_except "session" "locked" "tab" {{ - bind "{primary_modifier} o" {{ SwitchToMode "Session"; }} - }} - shared_except "tab" "locked" {{ - bind "{primary_modifier} t" {{ SwitchToMode "Tab"; }} - }} - shared_except "move" "locked" {{ - bind "{primary_modifier} m" {{ SwitchToMode "Move"; }} - }} - shared_except "tmux" "locked" {{ - bind "{primary_modifier} b" {{ SwitchToMode "Tmux"; }} - }} -}} -"# - ) -} diff --git a/default-plugins/configuration/src/presets.rs b/default-plugins/configuration/src/presets.rs new file mode 100644 index 00000000..fc8f84e1 --- /dev/null +++ b/default-plugins/configuration/src/presets.rs @@ -0,0 +1,1109 @@ +pub fn unlock_first_keybinds(primary_modifier: String, secondary_modifier: String) -> String { + format!( + r#" +default_mode "locked" +keybinds clear-defaults=true {{ + normal {{ + }} + locked {{ + bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} + }} + resize {{ + bind "r" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ Resize "Increase Left"; }} + bind "j" "Down" {{ Resize "Increase Down"; }} + bind "k" "Up" {{ Resize "Increase Up"; }} + bind "l" "Right" {{ Resize "Increase Right"; }} + bind "H" {{ Resize "Decrease Left"; }} + bind "J" {{ Resize "Decrease Down"; }} + bind "K" {{ Resize "Decrease Up"; }} + bind "L" {{ Resize "Decrease Right"; }} + bind "=" "+" {{ Resize "Increase"; }} + bind "-" {{ Resize "Decrease"; }} + }} + pane {{ + bind "p" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ MoveFocus "Left"; }} + bind "l" "Right" {{ MoveFocus "Right"; }} + bind "j" "Down" {{ MoveFocus "Down"; }} + bind "k" "Up" {{ MoveFocus "Up"; }} + bind "Tab" {{ SwitchFocus; }} + bind "n" {{ NewPane; SwitchToMode "Locked"; }} + bind "d" {{ NewPane "Down"; SwitchToMode "Locked"; }} + bind "r" {{ NewPane "Right"; SwitchToMode "Locked"; }} + bind "x" {{ CloseFocus; SwitchToMode "Locked"; }} + bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Locked"; }} + bind "z" {{ TogglePaneFrames; SwitchToMode "Locked"; }} + bind "w" {{ ToggleFloatingPanes; SwitchToMode "Locked"; }} + bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Locked"; }} + bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + }} + move {{ + bind "m" {{ SwitchToMode "Normal"; }} + bind "n" "Tab" {{ MovePane; }} + bind "p" {{ MovePaneBackwards; }} + bind "h" "Left" {{ MovePane "Left"; }} + bind "j" "Down" {{ MovePane "Down"; }} + bind "k" "Up" {{ MovePane "Up"; }} + bind "l" "Right" {{ MovePane "Right"; }} + }} + tab {{ + bind "t" {{ SwitchToMode "Normal"; }} + bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} + bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} + bind "l" "Right" "Down" "j" {{ GoToNextTab; }} + bind "n" {{ NewTab; SwitchToMode "Locked"; }} + bind "x" {{ CloseTab; SwitchToMode "Locked"; }} + bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Locked"; }} + bind "b" {{ BreakPane; SwitchToMode "Locked"; }} + bind "]" {{ BreakPaneRight; SwitchToMode "Locked"; }} + bind "[" {{ BreakPaneLeft; SwitchToMode "Locked"; }} + bind "1" {{ GoToTab 1; SwitchToMode "Locked"; }} + bind "2" {{ GoToTab 2; SwitchToMode "Locked"; }} + bind "3" {{ GoToTab 3; SwitchToMode "Locked"; }} + bind "4" {{ GoToTab 4; SwitchToMode "Locked"; }} + bind "5" {{ GoToTab 5; SwitchToMode "Locked"; }} + bind "6" {{ GoToTab 6; SwitchToMode "Locked"; }} + bind "7" {{ GoToTab 7; SwitchToMode "Locked"; }} + bind "8" {{ GoToTab 8; SwitchToMode "Locked"; }} + bind "9" {{ GoToTab 9; SwitchToMode "Locked"; }} + bind "Tab" {{ ToggleTab; }} + }} + scroll {{ + bind "s" {{ SwitchToMode "Normal"; }} + bind "e" {{ EditScrollback; SwitchToMode "Locked"; }} + bind "f" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Locked"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + }} + search {{ + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Locked"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + bind "n" {{ Search "down"; }} + bind "p" {{ Search "up"; }} + bind "c" {{ SearchToggleOption "CaseSensitivity"; }} + bind "w" {{ SearchToggleOption "Wrap"; }} + bind "o" {{ SearchToggleOption "WholeWord"; }} + }} + entersearch {{ + bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} + bind "Enter" {{ SwitchToMode "Search"; }} + }} + renametab {{ + bind "Ctrl c" "Enter" {{ SwitchToMode "Locked"; }} + bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} + }} + renamepane {{ + bind "Ctrl c" "Enter" {{ SwitchToMode "Locked"; }} + bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} + }} + session {{ + bind "o" {{ SwitchToMode "Normal"; }} + bind "d" {{ Detach; }} + bind "w" {{ + LaunchOrFocusPlugin "session-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Locked" + }} + bind "c" {{ + LaunchOrFocusPlugin "configuration" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Locked" + }} + bind "p" {{ + LaunchOrFocusPlugin "plugin-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Locked" + }} + }} + shared_except "locked" "renametab" "renamepane" {{ + bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} + bind "{primary_modifier} q" {{ Quit; }} + }} + shared_except "renamepane" "renametab" "entersearch" "locked" {{ + bind "esc" {{ SwitchToMode "locked"; }} + }} + shared_among "normal" "locked" {{ + bind "{secondary_modifier} n" {{ NewPane; }} + bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} + bind "{secondary_modifier} i" {{ MoveTab "Left"; }} + bind "{secondary_modifier} o" {{ MoveTab "Right"; }} + bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} + bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} + bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} + bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} + bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} + bind "{secondary_modifier} -" {{ Resize "Decrease"; }} + bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} + bind "{secondary_modifier} ]" {{ NextSwapLayout; }} + }} + shared_except "locked" "renametab" "renamepane" {{ + bind "Enter" {{ SwitchToMode "Locked"; }} + }} + shared_except "pane" "locked" "renametab" "renamepane" "entersearch" {{ + bind "p" {{ SwitchToMode "Pane"; }} + }} + shared_except "resize" "locked" "renametab" "renamepane" "entersearch" {{ + bind "r" {{ SwitchToMode "Resize"; }} + }} + shared_except "scroll" "locked" "renametab" "renamepane" "entersearch" {{ + bind "s" {{ SwitchToMode "Scroll"; }} + }} + shared_except "session" "locked" "renametab" "renamepane" "entersearch" {{ + bind "o" {{ SwitchToMode "Session"; }} + }} + shared_except "tab" "locked" "renametab" "renamepane" "entersearch" {{ + bind "t" {{ SwitchToMode "Tab"; }} + }} + shared_except "move" "locked" "renametab" "renamepane" "entersearch" {{ + bind "m" {{ SwitchToMode "Move"; }} + }} +}}"# + ) +} + +pub fn default_keybinds(primary_modifier: String, secondary_modifier: String) -> String { + if primary_modifier.is_empty() && secondary_modifier.is_empty() { + return default_keybinds_no_modifiers(); + } else if primary_modifier == secondary_modifier { + return non_colliding_default_keybinds(primary_modifier, secondary_modifier); + } else if primary_modifier.is_empty() { + return default_keybinds_no_primary_modifier(secondary_modifier); + } else if secondary_modifier.is_empty() { + return default_keybinds_no_secondary_modifier(primary_modifier); + } + format!( + r#" +default_mode "normal" +keybinds clear-defaults=true {{ + normal {{}} + locked {{ + bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} + }} + resize {{ + bind "{primary_modifier} n" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ Resize "Increase Left"; }} + bind "j" "Down" {{ Resize "Increase Down"; }} + bind "k" "Up" {{ Resize "Increase Up"; }} + bind "l" "Right" {{ Resize "Increase Right"; }} + bind "H" {{ Resize "Decrease Left"; }} + bind "J" {{ Resize "Decrease Down"; }} + bind "K" {{ Resize "Decrease Up"; }} + bind "L" {{ Resize "Decrease Right"; }} + bind "=" "+" {{ Resize "Increase"; }} + bind "-" {{ Resize "Decrease"; }} + }} + pane {{ + bind "{primary_modifier} p" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ MoveFocus "Left"; }} + bind "l" "Right" {{ MoveFocus "Right"; }} + bind "j" "Down" {{ MoveFocus "Down"; }} + bind "k" "Up" {{ MoveFocus "Up"; }} + bind "p" {{ SwitchFocus; }} + bind "n" {{ NewPane; SwitchToMode "Normal"; }} + bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} + bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} + bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} + bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + }} + move {{ + bind "{primary_modifier} h" {{ SwitchToMode "Normal"; }} + bind "n" "Tab" {{ MovePane; }} + bind "p" {{ MovePaneBackwards; }} + bind "h" "Left" {{ MovePane "Left"; }} + bind "j" "Down" {{ MovePane "Down"; }} + bind "k" "Up" {{ MovePane "Up"; }} + bind "l" "Right" {{ MovePane "Right"; }} + }} + tab {{ + bind "{primary_modifier} t" {{ SwitchToMode "Normal"; }} + bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} + bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} + bind "l" "Right" "Down" "j" {{ GoToNextTab; }} + bind "n" {{ NewTab; SwitchToMode "Normal"; }} + bind "x" {{ CloseTab; SwitchToMode "Normal"; }} + bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} + bind "b" {{ BreakPane; SwitchToMode "Normal"; }} + bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} + bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} + bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} + bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} + bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} + bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} + bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} + bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} + bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} + bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} + bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} + bind "Tab" {{ ToggleTab; }} + }} + scroll {{ + bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} + bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} + bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + }} + search {{ + bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + bind "n" {{ Search "down"; }} + bind "p" {{ Search "up"; }} + bind "c" {{ SearchToggleOption "CaseSensitivity"; }} + bind "w" {{ SearchToggleOption "Wrap"; }} + bind "o" {{ SearchToggleOption "WholeWord"; }} + }} + entersearch {{ + bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} + bind "Enter" {{ SwitchToMode "Search"; }} + }} + renametab {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} + }} + renamepane {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} + }} + session {{ + bind "{primary_modifier} o" {{ SwitchToMode "Normal"; }} + bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} + bind "d" {{ Detach; }} + bind "w" {{ + LaunchOrFocusPlugin "session-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "c" {{ + LaunchOrFocusPlugin "configuration" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "p" {{ + LaunchOrFocusPlugin "plugin-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + }} + tmux {{ + bind "[" {{ SwitchToMode "Scroll"; }} + bind "{primary_modifier} b" {{ Write 2; SwitchToMode "Normal"; }} + bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "c" {{ NewTab; SwitchToMode "Normal"; }} + bind "," {{ SwitchToMode "RenameTab"; }} + bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} + bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} + bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "o" {{ FocusNextPane; }} + bind "d" {{ Detach; }} + bind "Space" {{ NextSwapLayout; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + }} + shared_except "locked" {{ + bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} + bind "{primary_modifier} q" {{ Quit; }} + bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} + bind "{secondary_modifier} n" {{ NewPane; }} + bind "{secondary_modifier} i" {{ MoveTab "Left"; }} + bind "{secondary_modifier} o" {{ MoveTab "Right"; }} + bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} + bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} + bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} + bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} + bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} + bind "{secondary_modifier} -" {{ Resize "Decrease"; }} + bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} + bind "{secondary_modifier} ]" {{ NextSwapLayout; }} + }} + shared_except "normal" "locked" {{ + bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} + }} + shared_except "pane" "locked" {{ + bind "{primary_modifier} p" {{ SwitchToMode "Pane"; }} + }} + shared_except "resize" "locked" {{ + bind "{primary_modifier} n" {{ SwitchToMode "Resize"; }} + }} + shared_except "scroll" "locked" {{ + bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} + }} + shared_except "session" "locked" {{ + bind "{primary_modifier} o" {{ SwitchToMode "Session"; }} + }} + shared_except "tab" "locked" {{ + bind "{primary_modifier} t" {{ SwitchToMode "Tab"; }} + }} + shared_except "move" "locked" {{ + bind "{primary_modifier} h" {{ SwitchToMode "Move"; }} + }} + shared_except "tmux" "locked" {{ + bind "{primary_modifier} b" {{ SwitchToMode "Tmux"; }} + }} +}} +"# + ) +} + +pub fn default_keybinds_no_primary_modifier(secondary_modifier: String) -> String { + format!( + r#" +default_mode "normal" +keybinds clear-defaults=true {{ + normal {{}} + locked {{}} + resize {{ + bind "h" "Left" {{ Resize "Increase Left"; }} + bind "j" "Down" {{ Resize "Increase Down"; }} + bind "k" "Up" {{ Resize "Increase Up"; }} + bind "l" "Right" {{ Resize "Increase Right"; }} + bind "H" {{ Resize "Decrease Left"; }} + bind "J" {{ Resize "Decrease Down"; }} + bind "K" {{ Resize "Decrease Up"; }} + bind "L" {{ Resize "Decrease Right"; }} + bind "=" "+" {{ Resize "Increase"; }} + bind "-" {{ Resize "Decrease"; }} + }} + pane {{ + bind "h" "Left" {{ MoveFocus "Left"; }} + bind "l" "Right" {{ MoveFocus "Right"; }} + bind "j" "Down" {{ MoveFocus "Down"; }} + bind "k" "Up" {{ MoveFocus "Up"; }} + bind "p" {{ SwitchFocus; }} + bind "n" {{ NewPane; SwitchToMode "Normal"; }} + bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} + bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} + bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} + bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + }} + move {{ + bind "n" "Tab" {{ MovePane; }} + bind "p" {{ MovePaneBackwards; }} + bind "h" "Left" {{ MovePane "Left"; }} + bind "j" "Down" {{ MovePane "Down"; }} + bind "k" "Up" {{ MovePane "Up"; }} + bind "l" "Right" {{ MovePane "Right"; }} + }} + tab {{ + bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} + bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} + bind "l" "Right" "Down" "j" {{ GoToNextTab; }} + bind "n" {{ NewTab; SwitchToMode "Normal"; }} + bind "x" {{ CloseTab; SwitchToMode "Normal"; }} + bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} + bind "b" {{ BreakPane; SwitchToMode "Normal"; }} + bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} + bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} + bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} + bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} + bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} + bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} + bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} + bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} + bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} + bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} + bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} + bind "Tab" {{ ToggleTab; }} + }} + scroll {{ + bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} + bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + }} + search {{ + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + bind "n" {{ Search "down"; }} + bind "p" {{ Search "up"; }} + bind "c" {{ SearchToggleOption "CaseSensitivity"; }} + bind "w" {{ SearchToggleOption "Wrap"; }} + bind "o" {{ SearchToggleOption "WholeWord"; }} + }} + entersearch {{ + bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} + bind "Enter" {{ SwitchToMode "Search"; }} + }} + renametab {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} + }} + renamepane {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} + }} + session {{ + bind "d" {{ Detach; }} + bind "w" {{ + LaunchOrFocusPlugin "session-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "c" {{ + LaunchOrFocusPlugin "configuration" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "p" {{ + LaunchOrFocusPlugin "plugin-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + }} + tmux {{ + bind "[" {{ SwitchToMode "Scroll"; }} + bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "c" {{ NewTab; SwitchToMode "Normal"; }} + bind "," {{ SwitchToMode "RenameTab"; }} + bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} + bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} + bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "o" {{ FocusNextPane; }} + bind "d" {{ Detach; }} + bind "Space" {{ NextSwapLayout; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + }} + shared_except "locked" {{ + bind "{secondary_modifier} n" {{ NewPane; }} + bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} + bind "{secondary_modifier} i" {{ MoveTab "Left"; }} + bind "{secondary_modifier} o" {{ MoveTab "Right"; }} + bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} + bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} + bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} + bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} + bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} + bind "{secondary_modifier} -" {{ Resize "Decrease"; }} + bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} + bind "{secondary_modifier} ]" {{ NextSwapLayout; }} + }} + shared_except "normal" "locked" {{ + bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} + }} +}} +"# + ) +} + +pub fn default_keybinds_no_secondary_modifier(primary_modifier: String) -> String { + format!( + r#" +default_mode "normal" +keybinds clear-defaults=true {{ + normal {{}} + locked {{ + bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} + }} + resize {{ + bind "{primary_modifier} n" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ Resize "Increase Left"; }} + bind "j" "Down" {{ Resize "Increase Down"; }} + bind "k" "Up" {{ Resize "Increase Up"; }} + bind "l" "Right" {{ Resize "Increase Right"; }} + bind "H" {{ Resize "Decrease Left"; }} + bind "J" {{ Resize "Decrease Down"; }} + bind "K" {{ Resize "Decrease Up"; }} + bind "L" {{ Resize "Decrease Right"; }} + bind "=" "+" {{ Resize "Increase"; }} + bind "-" {{ Resize "Decrease"; }} + }} + pane {{ + bind "{primary_modifier} p" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ MoveFocus "Left"; }} + bind "l" "Right" {{ MoveFocus "Right"; }} + bind "j" "Down" {{ MoveFocus "Down"; }} + bind "k" "Up" {{ MoveFocus "Up"; }} + bind "p" {{ SwitchFocus; }} + bind "n" {{ NewPane; SwitchToMode "Normal"; }} + bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} + bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} + bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} + bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + }} + move {{ + bind "{primary_modifier} h" {{ SwitchToMode "Normal"; }} + bind "n" "Tab" {{ MovePane; }} + bind "p" {{ MovePaneBackwards; }} + bind "h" "Left" {{ MovePane "Left"; }} + bind "j" "Down" {{ MovePane "Down"; }} + bind "k" "Up" {{ MovePane "Up"; }} + bind "l" "Right" {{ MovePane "Right"; }} + }} + tab {{ + bind "{primary_modifier} t" {{ SwitchToMode "Normal"; }} + bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} + bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} + bind "l" "Right" "Down" "j" {{ GoToNextTab; }} + bind "n" {{ NewTab; SwitchToMode "Normal"; }} + bind "x" {{ CloseTab; SwitchToMode "Normal"; }} + bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} + bind "b" {{ BreakPane; SwitchToMode "Normal"; }} + bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} + bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} + bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} + bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} + bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} + bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} + bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} + bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} + bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} + bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} + bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} + bind "Tab" {{ ToggleTab; }} + }} + scroll {{ + bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} + bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} + bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + }} + search {{ + bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + bind "n" {{ Search "down"; }} + bind "p" {{ Search "up"; }} + bind "c" {{ SearchToggleOption "CaseSensitivity"; }} + bind "w" {{ SearchToggleOption "Wrap"; }} + bind "o" {{ SearchToggleOption "WholeWord"; }} + }} + entersearch {{ + bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} + bind "Enter" {{ SwitchToMode "Search"; }} + }} + renametab {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} + }} + renamepane {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} + }} + session {{ + bind "{primary_modifier} o" {{ SwitchToMode "Normal"; }} + bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} + bind "d" {{ Detach; }} + bind "w" {{ + LaunchOrFocusPlugin "session-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "c" {{ + LaunchOrFocusPlugin "configuration" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "p" {{ + LaunchOrFocusPlugin "plugin-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + }} + tmux {{ + bind "[" {{ SwitchToMode "Scroll"; }} + bind "{primary_modifier} b" {{ Write 2; SwitchToMode "Normal"; }} + bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "c" {{ NewTab; SwitchToMode "Normal"; }} + bind "," {{ SwitchToMode "RenameTab"; }} + bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} + bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} + bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "o" {{ FocusNextPane; }} + bind "d" {{ Detach; }} + bind "Space" {{ NextSwapLayout; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + }} + shared_except "locked" {{ + bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} + bind "{primary_modifier} q" {{ Quit; }} + }} + shared_except "normal" "locked" {{ + bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} + }} + shared_except "pane" "locked" {{ + bind "{primary_modifier} p" {{ SwitchToMode "Pane"; }} + }} + shared_except "resize" "locked" {{ + bind "{primary_modifier} n" {{ SwitchToMode "Resize"; }} + }} + shared_except "scroll" "locked" {{ + bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} + }} + shared_except "session" "locked" {{ + bind "{primary_modifier} o" {{ SwitchToMode "Session"; }} + }} + shared_except "tab" "locked" {{ + bind "{primary_modifier} t" {{ SwitchToMode "Tab"; }} + }} + shared_except "move" "locked" {{ + bind "{primary_modifier} h" {{ SwitchToMode "Move"; }} + }} + shared_except "tmux" "locked" {{ + bind "{primary_modifier} b" {{ SwitchToMode "Tmux"; }} + }} +}} +"# + ) +} + +pub fn default_keybinds_no_modifiers() -> String { + format!( + r#" +default_mode "normal" +keybinds clear-defaults=true {{ + normal {{}} + locked {{}} + resize {{ + bind "h" "Left" {{ Resize "Increase Left"; }} + bind "j" "Down" {{ Resize "Increase Down"; }} + bind "k" "Up" {{ Resize "Increase Up"; }} + bind "l" "Right" {{ Resize "Increase Right"; }} + bind "H" {{ Resize "Decrease Left"; }} + bind "J" {{ Resize "Decrease Down"; }} + bind "K" {{ Resize "Decrease Up"; }} + bind "L" {{ Resize "Decrease Right"; }} + bind "=" "+" {{ Resize "Increase"; }} + bind "-" {{ Resize "Decrease"; }} + }} + pane {{ + bind "h" "Left" {{ MoveFocus "Left"; }} + bind "l" "Right" {{ MoveFocus "Right"; }} + bind "j" "Down" {{ MoveFocus "Down"; }} + bind "k" "Up" {{ MoveFocus "Up"; }} + bind "p" {{ SwitchFocus; }} + bind "n" {{ NewPane; SwitchToMode "Normal"; }} + bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} + bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} + bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} + bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + }} + move {{ + bind "n" "Tab" {{ MovePane; }} + bind "p" {{ MovePaneBackwards; }} + bind "h" "Left" {{ MovePane "Left"; }} + bind "j" "Down" {{ MovePane "Down"; }} + bind "k" "Up" {{ MovePane "Up"; }} + bind "l" "Right" {{ MovePane "Right"; }} + }} + tab {{ + bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} + bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} + bind "l" "Right" "Down" "j" {{ GoToNextTab; }} + bind "n" {{ NewTab; SwitchToMode "Normal"; }} + bind "x" {{ CloseTab; SwitchToMode "Normal"; }} + bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} + bind "b" {{ BreakPane; SwitchToMode "Normal"; }} + bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} + bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} + bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} + bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} + bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} + bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} + bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} + bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} + bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} + bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} + bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} + bind "Tab" {{ ToggleTab; }} + }} + scroll {{ + bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} + bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + }} + search {{ + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + bind "n" {{ Search "down"; }} + bind "p" {{ Search "up"; }} + bind "c" {{ SearchToggleOption "CaseSensitivity"; }} + bind "w" {{ SearchToggleOption "Wrap"; }} + bind "o" {{ SearchToggleOption "WholeWord"; }} + }} + entersearch {{ + bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} + bind "Enter" {{ SwitchToMode "Search"; }} + }} + renametab {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} + }} + renamepane {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} + }} + session {{ + bind "d" {{ Detach; }} + bind "w" {{ + LaunchOrFocusPlugin "session-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "c" {{ + LaunchOrFocusPlugin "configuration" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "p" {{ + LaunchOrFocusPlugin "plugin-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + }} + tmux {{ + bind "[" {{ SwitchToMode "Scroll"; }} + bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "c" {{ NewTab; SwitchToMode "Normal"; }} + bind "," {{ SwitchToMode "RenameTab"; }} + bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} + bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} + bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "o" {{ FocusNextPane; }} + bind "d" {{ Detach; }} + bind "Space" {{ NextSwapLayout; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + }} + shared_except "normal" "locked" {{ + bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} + }} +}} +"# + ) +} + +pub fn non_colliding_default_keybinds( + primary_modifier: String, + secondary_modifier: String, +) -> String { + format!( + r#" +default_mode "normal" +keybinds clear-defaults=true {{ + normal {{}} + locked {{ + bind "{primary_modifier} g" {{ SwitchToMode "Normal"; }} + }} + resize {{ + bind "{primary_modifier} r" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ Resize "Increase Left"; }} + bind "j" "Down" {{ Resize "Increase Down"; }} + bind "k" "Up" {{ Resize "Increase Up"; }} + bind "l" "Right" {{ Resize "Increase Right"; }} + bind "H" {{ Resize "Decrease Left"; }} + bind "J" {{ Resize "Decrease Down"; }} + bind "K" {{ Resize "Decrease Up"; }} + bind "L" {{ Resize "Decrease Right"; }} + bind "=" "+" {{ Resize "Increase"; }} + bind "-" {{ Resize "Decrease"; }} + }} + pane {{ + bind "{primary_modifier} p" {{ SwitchToMode "Normal"; }} + bind "h" "Left" {{ MoveFocus "Left"; }} + bind "l" "Right" {{ MoveFocus "Right"; }} + bind "j" "Down" {{ MoveFocus "Down"; }} + bind "k" "Up" {{ MoveFocus "Up"; }} + bind "p" {{ SwitchFocus; }} + bind "n" {{ NewPane; SwitchToMode "Normal"; }} + bind "d" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "r" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + bind "f" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "z" {{ TogglePaneFrames; SwitchToMode "Normal"; }} + bind "w" {{ ToggleFloatingPanes; SwitchToMode "Normal"; }} + bind "e" {{ TogglePaneEmbedOrFloating; SwitchToMode "Normal"; }} + bind "c" {{ SwitchToMode "RenamePane"; PaneNameInput 0;}} + }} + move {{ + bind "{primary_modifier} m" {{ SwitchToMode "Normal"; }} + bind "n" "Tab" {{ MovePane; }} + bind "p" {{ MovePaneBackwards; }} + bind "h" "Left" {{ MovePane "Left"; }} + bind "j" "Down" {{ MovePane "Down"; }} + bind "k" "Up" {{ MovePane "Up"; }} + bind "l" "Right" {{ MovePane "Right"; }} + }} + tab {{ + bind "{primary_modifier} t" {{ SwitchToMode "Normal"; }} + bind "r" {{ SwitchToMode "RenameTab"; TabNameInput 0; }} + bind "h" "Left" "Up" "k" {{ GoToPreviousTab; }} + bind "l" "Right" "Down" "j" {{ GoToNextTab; }} + bind "n" {{ NewTab; SwitchToMode "Normal"; }} + bind "x" {{ CloseTab; SwitchToMode "Normal"; }} + bind "s" {{ ToggleActiveSyncTab; SwitchToMode "Normal"; }} + bind "b" {{ BreakPane; SwitchToMode "Normal"; }} + bind "]" {{ BreakPaneRight; SwitchToMode "Normal"; }} + bind "[" {{ BreakPaneLeft; SwitchToMode "Normal"; }} + bind "1" {{ GoToTab 1; SwitchToMode "Normal"; }} + bind "2" {{ GoToTab 2; SwitchToMode "Normal"; }} + bind "3" {{ GoToTab 3; SwitchToMode "Normal"; }} + bind "4" {{ GoToTab 4; SwitchToMode "Normal"; }} + bind "5" {{ GoToTab 5; SwitchToMode "Normal"; }} + bind "6" {{ GoToTab 6; SwitchToMode "Normal"; }} + bind "7" {{ GoToTab 7; SwitchToMode "Normal"; }} + bind "8" {{ GoToTab 8; SwitchToMode "Normal"; }} + bind "9" {{ GoToTab 9; SwitchToMode "Normal"; }} + bind "Tab" {{ ToggleTab; }} + }} + scroll {{ + bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} + bind "e" {{ EditScrollback; SwitchToMode "Normal"; }} + bind "s" {{ SwitchToMode "EnterSearch"; SearchInput 0; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + }} + search {{ + bind "{primary_modifier} s" {{ SwitchToMode "Normal"; }} + bind "Ctrl c" {{ ScrollToBottom; SwitchToMode "Normal"; }} + bind "j" "Down" {{ ScrollDown; }} + bind "k" "Up" {{ ScrollUp; }} + bind "Ctrl f" "PageDown" "Right" "l" {{ PageScrollDown; }} + bind "Ctrl b" "PageUp" "Left" "h" {{ PageScrollUp; }} + bind "d" {{ HalfPageScrollDown; }} + bind "u" {{ HalfPageScrollUp; }} + bind "n" {{ Search "down"; }} + bind "p" {{ Search "up"; }} + bind "c" {{ SearchToggleOption "CaseSensitivity"; }} + bind "w" {{ SearchToggleOption "Wrap"; }} + bind "o" {{ SearchToggleOption "WholeWord"; }} + }} + entersearch {{ + bind "Ctrl c" "Esc" {{ SwitchToMode "Scroll"; }} + bind "Enter" {{ SwitchToMode "Search"; }} + }} + renametab {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenameTab; SwitchToMode "Tab"; }} + }} + renamepane {{ + bind "Ctrl c" {{ SwitchToMode "Normal"; }} + bind "Esc" {{ UndoRenamePane; SwitchToMode "Pane"; }} + }} + session {{ + bind "{primary_modifier} o" {{ SwitchToMode "Normal"; }} + bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} + bind "d" {{ Detach; }} + bind "w" {{ + LaunchOrFocusPlugin "session-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "c" {{ + LaunchOrFocusPlugin "configuration" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + bind "p" {{ + LaunchOrFocusPlugin "plugin-manager" {{ + floating true + move_to_focused_tab true + }}; + SwitchToMode "Normal" + }} + }} + tmux {{ + bind "[" {{ SwitchToMode "Scroll"; }} + bind "{primary_modifier} b" {{ Write 2; SwitchToMode "Normal"; }} + bind "\"" {{ NewPane "Down"; SwitchToMode "Normal"; }} + bind "%" {{ NewPane "Right"; SwitchToMode "Normal"; }} + bind "z" {{ ToggleFocusFullscreen; SwitchToMode "Normal"; }} + bind "c" {{ NewTab; SwitchToMode "Normal"; }} + bind "," {{ SwitchToMode "RenameTab"; }} + bind "p" {{ GoToPreviousTab; SwitchToMode "Normal"; }} + bind "n" {{ GoToNextTab; SwitchToMode "Normal"; }} + bind "Left" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "Right" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "Down" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "Up" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "h" {{ MoveFocus "Left"; SwitchToMode "Normal"; }} + bind "l" {{ MoveFocus "Right"; SwitchToMode "Normal"; }} + bind "j" {{ MoveFocus "Down"; SwitchToMode "Normal"; }} + bind "k" {{ MoveFocus "Up"; SwitchToMode "Normal"; }} + bind "o" {{ FocusNextPane; }} + bind "d" {{ Detach; }} + bind "Space" {{ NextSwapLayout; }} + bind "x" {{ CloseFocus; SwitchToMode "Normal"; }} + }} + shared_except "locked" {{ + bind "{primary_modifier} g" {{ SwitchToMode "Locked"; }} + bind "{primary_modifier} q" {{ Quit; }} + bind "{secondary_modifier} f" {{ ToggleFloatingPanes; }} + bind "{secondary_modifier} n" {{ NewPane; }} + bind "{secondary_modifier} i" {{ MoveTab "Left"; }} + bind "{secondary_modifier} o" {{ MoveTab "Right"; }} + bind "{secondary_modifier} h" "{secondary_modifier} Left" {{ MoveFocusOrTab "Left"; }} + bind "{secondary_modifier} l" "{secondary_modifier} Right" {{ MoveFocusOrTab "Right"; }} + bind "{secondary_modifier} j" "{secondary_modifier} Down" {{ MoveFocus "Down"; }} + bind "{secondary_modifier} k" "{secondary_modifier} Up" {{ MoveFocus "Up"; }} + bind "{secondary_modifier} =" "{secondary_modifier} +" {{ Resize "Increase"; }} + bind "{secondary_modifier} -" {{ Resize "Decrease"; }} + bind "{secondary_modifier} [" {{ PreviousSwapLayout; }} + bind "{secondary_modifier} ]" {{ NextSwapLayout; }} + }} + shared_except "normal" "locked" {{ + bind "Enter" "Esc" {{ SwitchToMode "Normal"; }} + }} + shared_except "pane" "locked" {{ + bind "{primary_modifier} p" {{ SwitchToMode "Pane"; }} + }} + shared_except "resize" "locked" {{ + bind "{primary_modifier} r" {{ SwitchToMode "Resize"; }} + }} + shared_except "scroll" "locked" {{ + bind "{primary_modifier} s" {{ SwitchToMode "Scroll"; }} + }} + shared_except "session" "locked" "tab" {{ + bind "{primary_modifier} o" {{ SwitchToMode "Session"; }} + }} + shared_except "tab" "locked" {{ + bind "{primary_modifier} t" {{ SwitchToMode "Tab"; }} + }} + shared_except "move" "locked" {{ + bind "{primary_modifier} m" {{ SwitchToMode "Move"; }} + }} + shared_except "tmux" "locked" {{ + bind "{primary_modifier} b" {{ SwitchToMode "Tmux"; }} + }} +}} +"# + ) +} diff --git a/default-plugins/configuration/src/presets_screen.rs b/default-plugins/configuration/src/presets_screen.rs new file mode 100644 index 00000000..5cdc4c02 --- /dev/null +++ b/default-plugins/configuration/src/presets_screen.rs @@ -0,0 +1,846 @@ +use zellij_tile::prelude::*; + +use crate::ui_components::info_line; + +use crate::rebind_leaders_screen::RebindLeadersScreen; +use std::collections::BTreeSet; + +use crate::presets::{default_keybinds, unlock_first_keybinds}; + +#[derive(Debug)] +pub struct PresetsScreen { + selected_index: Option, + latest_mode_info: Option, + notification: Option, + primary_modifier: BTreeSet, + secondary_modifier: BTreeSet, + rebind_leaders_screen: Option, +} + +impl Default for PresetsScreen { + 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); + PresetsScreen { + primary_modifier, + secondary_modifier, + selected_index: None, + latest_mode_info: None, + notification: None, + rebind_leaders_screen: None, + } + } +} + +impl PresetsScreen { + pub fn new(selected_index: Option) -> Self { + PresetsScreen { + selected_index, + ..Default::default() + } + } + pub fn rebinding_leaders(&self) -> bool { + self.rebind_leaders_screen.is_some() + } + pub fn handle_presets_key(&mut self, key: KeyWithModifier) -> bool { + if let Some(rebind_leaders_screen) = self.rebind_leaders_screen.as_mut() { + match key.bare_key { + BareKey::Esc if key.has_no_modifiers() => { + // consume screen without applying its modifiers + drop(self.rebind_leaders_screen.take()); + return true; + }, + BareKey::Enter if key.has_no_modifiers() => { + // consume screen and apply its modifiers + let (primary_modifier, secondary_modifier) = + rebind_leaders_screen.primary_and_secondary_modifiers(); + self.primary_modifier = primary_modifier; + self.secondary_modifier = secondary_modifier; + drop(self.rebind_leaders_screen.take()); + return true; + }, + _ => { + return rebind_leaders_screen.handle_key(key); + }, + } + } + let mut should_render = false; + if self.notification.is_some() { + self.notification = None; + should_render = true; + } else if key.bare_key == BareKey::Down && key.has_no_modifiers() { + self.move_selected_index_down(); + should_render = true; + } else if key.bare_key == BareKey::Up && key.has_no_modifiers() { + self.move_selected_index_up(); + should_render = true; + } else if key.bare_key == BareKey::Enter && key.has_no_modifiers() { + if let Some(selected_index) = self.selected_index.take() { + let write_to_disk = false; + self.reconfigure(selected_index, write_to_disk); + self.notification = Some("Configuration applied to current session.".to_owned()); + } else { + self.reset_selected_index(); + } + should_render = true; + } else if key.bare_key == BareKey::Insert && key.has_no_modifiers() { + if let Some(selected_index) = self.take_selected_index() { + let write_to_disk = true; + self.reconfigure(selected_index, write_to_disk); + self.notification = Some("Configuration applied and saved to disk.".to_owned()); + should_render = true; + } + } else if key.bare_key == BareKey::Char('l') && key.has_no_modifiers() { + self.rebind_leaders_screen = Some( + RebindLeadersScreen::default() + .with_rebinding_for_presets() + .with_mode_info(self.latest_mode_info.clone()), + ); + should_render = true; + } else if (key.bare_key == BareKey::Esc && key.has_no_modifiers()) + || key.is_key_with_ctrl_modifier(BareKey::Char('c')) + { + close_self(); + should_render = true; + } + should_render + } + pub fn handle_setup_wizard_key(&mut self, key: KeyWithModifier) -> bool { + if let Some(rebind_leaders_screen) = self.rebind_leaders_screen.as_mut() { + match key.bare_key { + BareKey::Esc if key.has_no_modifiers() => { + // consume screen without applying its modifiers + drop(self.rebind_leaders_screen.take()); + return true; + }, + BareKey::Enter if key.has_no_modifiers() => { + // consume screen and apply its modifiers + let (primary_modifier, secondary_modifier) = + rebind_leaders_screen.primary_and_secondary_modifiers(); + self.primary_modifier = primary_modifier; + self.secondary_modifier = secondary_modifier; + drop(self.rebind_leaders_screen.take()); + return true; + }, + _ => { + return rebind_leaders_screen.handle_key(key); + }, + } + } + let mut should_render = false; + if self.notification.is_some() { + self.notification = None; + should_render = true; + } else if key.bare_key == BareKey::Down && key.has_no_modifiers() { + self.move_selected_index_down(); + should_render = true; + } else if key.bare_key == BareKey::Up && key.has_no_modifiers() { + self.move_selected_index_up(); + should_render = true; + } else if key.bare_key == BareKey::Enter && key.has_no_modifiers() { + if let Some(selected_index) = self.take_selected_index() { + let write_to_disk = true; + self.reconfigure(selected_index, write_to_disk); + close_self(); + } else { + self.reset_selected_index(); + should_render = true; + } + } else if key.bare_key == BareKey::Char('l') && key.has_no_modifiers() { + self.rebind_leaders_screen = + Some(RebindLeadersScreen::default().with_rebinding_for_presets()); + should_render = true; + } else if (key.bare_key == BareKey::Esc && key.has_no_modifiers()) + || key.is_key_with_ctrl_modifier(BareKey::Char('c')) + { + close_self(); + should_render = true; + } + should_render + } + pub fn update_mode_info(&mut self, mode_info: ModeInfo) { + if let Some(rebind_leaders_screen) = self.rebind_leaders_screen.as_mut() { + rebind_leaders_screen.update_mode_info(mode_info.clone()); + } + self.latest_mode_info = Some(mode_info); + } + pub fn move_selected_index_down(&mut self) { + if self.selected_index.is_none() { + self.selected_index = Some(0); + } else if self.selected_index < Some(1) { + self.selected_index = Some(1); + } else { + self.selected_index = None; + } + } + pub fn move_selected_index_up(&mut self) { + if self.selected_index.is_none() { + self.selected_index = Some(1); + } else if self.selected_index == Some(1) { + self.selected_index = Some(0); + } else { + self.selected_index = None; + } + } + pub fn take_selected_index(&mut self) -> Option { + self.selected_index.take() + } + pub fn reset_selected_index(&mut self) { + self.selected_index = Some(0); + } + fn reconfigure(&self, selected: usize, write_to_disk: bool) { + if selected == 0 { + // TODO: these should be part of a "transaction" when they are + // implemented + reconfigure( + default_keybinds( + self.primary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(" "), + self.secondary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(" "), + ), + write_to_disk, + ); + switch_to_input_mode(&InputMode::Normal); + } else if selected == 1 { + // TODO: these should be part of a "transaction" when they are + // implemented + reconfigure( + unlock_first_keybinds( + self.primary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(" "), + self.secondary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .join(" "), + ), + write_to_disk, + ); + switch_to_input_mode(&InputMode::Locked); + } + } + pub fn render_setup_wizard_screen( + &mut self, + rows: usize, + cols: usize, + ui_size: usize, + notification: &Option, + ) { + if let Some(rebind_leaders_screen) = self.rebind_leaders_screen.as_mut() { + return rebind_leaders_screen.render(rows, cols, ui_size, notification); + } + let primary_modifier_key_text = self.primary_modifier_text(); + let secondary_modifier_key_text = self.secondary_modifier_text(); + self.render_setup_wizard_title(rows, cols, &primary_modifier_key_text, ui_size); + self.render_first_bulletin(rows + 8, cols, &primary_modifier_key_text, ui_size); + self.render_second_bulletin(rows + 8, cols, &primary_modifier_key_text, ui_size); + self.render_leader_keys_indication( + rows + 8, + cols, + &primary_modifier_key_text, + &secondary_modifier_key_text, + ui_size, + ); + info_line( + rows + 8, + cols, + ui_size, + ¬ification, + &self.warning_text(cols), + Some(self.main_screen_widths(&primary_modifier_key_text)), + ); + // self.render_info_line(rows + 8, cols); + self.render_help_text_setup_wizard(rows + 8, cols); + } + pub fn render_reset_keybindings_screen( + &mut self, + rows: usize, + cols: usize, + ui_size: usize, + notification: &Option, + ) { + if let Some(rebind_leaders_screen) = self.rebind_leaders_screen.as_mut() { + return rebind_leaders_screen.render(rows, cols, ui_size, notification); + } + let primary_modifier_key_text = self.primary_modifier_text(); + let secondary_modifier_key_text = self.secondary_modifier_text(); + self.render_override_title(rows, cols, &primary_modifier_key_text, ui_size); + self.render_first_bulletin(rows, cols, &primary_modifier_key_text, ui_size); + self.render_second_bulletin(rows, cols, &primary_modifier_key_text, ui_size); + self.render_leader_keys_indication( + rows, + cols, + &primary_modifier_key_text, + &secondary_modifier_key_text, + ui_size, + ); + let notification = notification.clone().or_else(|| self.notification.clone()); + let warning_text = self.warning_text(cols); + info_line( + rows, + cols, + ui_size, + ¬ification, + &warning_text, + Some(self.main_screen_widths(&primary_modifier_key_text)), + ); + self.render_help_text_main(rows, cols); + } + fn primary_modifier_text(&self) -> String { + if self.primary_modifier.is_empty() { + "".to_owned() + } else { + self.primary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .join("-") + } + } + fn secondary_modifier_text(&self) -> String { + if self.secondary_modifier.is_empty() { + "".to_owned() + } else { + self.secondary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .join("-") + } + } + fn render_setup_wizard_title( + &self, + rows: usize, + cols: usize, + primary_modifier_key_text: &str, + ui_size: usize, + ) { + let widths = self.main_screen_widths(primary_modifier_key_text); + if cols >= widths.0 { + let title_text_1 = "Hi there! How would you like to interact with Zellij?"; + let title_text_2 = "Not sure? Press to choose Default."; + let title_text_3 = "Everything can always be changed later."; + let title_text_4 = "Tips appear on screen - you don't need to remember anything."; + let left_padding = cols.saturating_sub(widths.0) / 2; + let first_row_coords = (rows.saturating_sub(ui_size) / 2).saturating_sub(1); + print_text_with_coordinates( + Text::new(title_text_1).color_range(2, ..), + left_padding, + first_row_coords, + None, + None, + ); + print_text_with_coordinates( + Text::new(title_text_2) + .color_range(0, ..10) + .color_range(2, 16..23) + .color_range(1, 34..41), + left_padding, + first_row_coords + 2, + None, + None, + ); + print_text_with_coordinates( + Text::new(title_text_3), + left_padding, + first_row_coords + 4, + None, + None, + ); + print_text_with_coordinates( + Text::new(title_text_4), + left_padding, + first_row_coords + 5, + None, + None, + ); + } else { + let title_text_1 = "Hi there! Which do you prefer?"; + let title_text_2 = "Not sure? Press "; + let title_text_3 = "Can be changed later. Tips appear"; + let title_text_4 = "on screen - no need to remember"; + let left_padding = if cols >= widths.1 { + cols.saturating_sub(widths.1) / 2 + } else { + cols.saturating_sub(widths.2) / 2 + }; + let first_row_coords = (rows.saturating_sub(ui_size) / 2).saturating_sub(1); + print_text_with_coordinates( + Text::new(title_text_1).color_range(2, ..), + left_padding, + first_row_coords, + None, + None, + ); + print_text_with_coordinates( + Text::new(title_text_2) + .color_range(0, ..10) + .color_range(2, 16..23) + .color_range(1, 40..49), + left_padding, + first_row_coords + 2, + None, + None, + ); + print_text_with_coordinates( + Text::new(title_text_3), + left_padding, + first_row_coords + 4, + None, + None, + ); + print_text_with_coordinates( + Text::new(title_text_4), + left_padding, + first_row_coords + 5, + None, + None, + ); + } + } + fn main_screen_widths(&self, primary_modifier_text: &str) -> (usize, usize, usize) { + let primary_modifier_key_text_len = primary_modifier_text.chars().count(); + let full_width = 61 + primary_modifier_key_text_len; + let mid_width = 36 + primary_modifier_key_text_len; + let min_width = 26 + primary_modifier_key_text_len; + (full_width, mid_width, min_width) + } + fn render_first_bulletin( + &self, + rows: usize, + cols: usize, + primary_modifier_key_text: &str, + ui_size: usize, + ) { + let widths = self.main_screen_widths(primary_modifier_key_text); + let primary_modifier_key_text_len = primary_modifier_key_text.chars().count(); + let default_text = "1. Default"; + let (mut list_items, max_width) = if cols >= widths.0 { + let list_items = vec![ + NestedListItem::new(default_text).color_range(1, ..), + NestedListItem::new("All modes available directly from the base mode, eg.:") + .indent(1), + NestedListItem::new(format!( + "{} p - to enter PANE mode", + primary_modifier_key_text + )) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 2, + primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 18, + ) + .indent(1), + NestedListItem::new(format!( + "{} t - to enter TAB mode", + primary_modifier_key_text + )) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 2, + primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 17, + ) + .indent(1), + ]; + let max_width = widths.0; + (list_items, max_width) + } else if cols >= widths.1 { + let list_items = vec![ + NestedListItem::new(default_text).color_range(1, ..), + NestedListItem::new("Modes available directly, eg.:").indent(1), + NestedListItem::new(format!( + "{} p - to enter PANE mode", + primary_modifier_key_text + )) + .indent(1) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 2, + primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 18, + ), + NestedListItem::new(format!( + "{} t - to enter TAB mode", + primary_modifier_key_text + )) + .indent(1) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 2, + primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 17, + ), + ]; + let max_width = widths.1; + (list_items, max_width) + } else { + let list_items = vec![ + NestedListItem::new(default_text).color_range(1, ..), + NestedListItem::new("Directly, eg.:").indent(1), + NestedListItem::new(format!("{} p - PANE mode", primary_modifier_key_text)) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 2, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 10, + ) + .indent(1), + NestedListItem::new(format!("{} t - TAB mode", primary_modifier_key_text)) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 2, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 9, + ) + .indent(1), + ]; + let max_width = widths.2; + (list_items, max_width) + }; + if self.selected_index == Some(0) { + list_items = list_items.drain(..).map(|i| i.selected()).collect(); + } + let left_padding = cols.saturating_sub(max_width) / 2; + let top_coordinates = if rows > 14 { + (rows.saturating_sub(ui_size) / 2) + 3 + } else { + (rows.saturating_sub(ui_size) / 2) + 2 + }; + print_nested_list_with_coordinates( + list_items, + left_padding, + top_coordinates, + Some(max_width), + None, + ); + } + fn render_second_bulletin( + &self, + rows: usize, + cols: usize, + primary_modifier_key_text: &str, + ui_size: usize, + ) { + let unlock_first_text = "2. Unlock First (non-colliding)"; + let widths = self.main_screen_widths(primary_modifier_key_text); + let primary_modifier_key_text_len = primary_modifier_key_text.chars().count(); + let (mut list_items, max_width) = if cols >= widths.0 { + let list_items = vec![ + NestedListItem::new(unlock_first_text).color_range(1, ..), + NestedListItem::new(format!( + "Single key modes available after unlocking with {} g, eg.:", + primary_modifier_key_text + )) + .indent(1), + NestedListItem::new(format!( + "{} g + p to enter PANE mode", + primary_modifier_key_text + )) + .indent(1) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 3, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, + ) + .color_range( + 2, + primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 21, + ), + NestedListItem::new(format!( + "{} g + t to enter TAB mode", + primary_modifier_key_text + )) + .indent(1) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 3, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, + ) + .color_range( + 2, + primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 20, + ), + ]; + let max_width = widths.0; + (list_items, max_width) + } else if cols >= widths.1 { + let list_items = vec![ + NestedListItem::new(unlock_first_text).color_range(1, ..), + NestedListItem::new(format!( + "Single key modes after {} g, eg.:", + primary_modifier_key_text + )) + .indent(1), + NestedListItem::new(format!( + "{} g + p to enter PANE mode", + primary_modifier_key_text + )) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 3, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, + ) + .color_range( + 2, + primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 21, + ) + .indent(1), + NestedListItem::new(format!( + "{} g + t to enter TAB mode", + primary_modifier_key_text + )) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 3, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, + ) + .color_range( + 2, + primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 20, + ) + .indent(1), + ]; + let max_width = widths.1; + (list_items, max_width) + } else { + let list_items = vec![ + NestedListItem::new("2. Unlock First").color_range(1, ..), + NestedListItem::new(format!( + "{} g + single key, eg.:", + primary_modifier_key_text + )) + .indent(1), + NestedListItem::new(format!("{} g + p PANE mode", primary_modifier_key_text)) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 3, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, + ) + .color_range( + 2, + primary_modifier_key_text_len + 7..primary_modifier_key_text_len + 11, + ) + .indent(1), + NestedListItem::new(format!("{} g + t TAB mode", primary_modifier_key_text)) + .color_range(3, ..primary_modifier_key_text_len + 3) + .color_range( + 3, + primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 7, + ) + .color_range( + 2, + primary_modifier_key_text_len + 7..primary_modifier_key_text_len + 10, + ) + .indent(1), + ]; + let max_width = widths.2; + (list_items, max_width) + }; + if self.selected_index == Some(1) { + list_items = list_items.drain(..).map(|i| i.selected()).collect(); + } + let left_padding = cols.saturating_sub(max_width) / 2; + let top_coordinates = if rows > 14 { + (rows.saturating_sub(ui_size) / 2) + 8 + } else { + (rows.saturating_sub(ui_size) / 2) + 6 + }; + print_nested_list_with_coordinates( + list_items, + left_padding, + top_coordinates, + Some(max_width), + None, + ); + } + fn render_leader_keys_indication( + &self, + rows: usize, + cols: usize, + primary_modifier_key_text: &str, + secondary_modifier_key_text: &str, + ui_size: usize, + ) { + let widths = self.main_screen_widths(primary_modifier_key_text); + let primary_modifier_key_text_len = primary_modifier_key_text.chars().count(); + let secondary_modifier_key_text_len = secondary_modifier_key_text.chars().count(); + let top_coordinates = if rows > 14 { + (rows.saturating_sub(ui_size) / 2) + 13 + } else { + (rows.saturating_sub(ui_size) / 2) + 10 + }; + + if cols >= widths.0 { + let leader_key_text = format!( + "Leader keys: {} - modes, {} - quicknav and shortcuts", + primary_modifier_key_text, secondary_modifier_key_text + ); + let left_padding = cols.saturating_sub(widths.0) / 2; + print_text_with_coordinates( + Text::new(leader_key_text) + .color_range(2, ..12) + .color_range(3, 13..primary_modifier_key_text_len + 14) + .color_range( + 0, + primary_modifier_key_text_len + 23 + ..primary_modifier_key_text_len + 23 + secondary_modifier_key_text_len, + ), + left_padding, + top_coordinates, + None, + None, + ) + } else { + let leader_key_text = format!( + "Leaders: {}, {}", + primary_modifier_key_text, secondary_modifier_key_text + ); + let left_padding = if cols >= widths.1 { + cols.saturating_sub(widths.1) / 2 + } else { + cols.saturating_sub(widths.2) / 2 + }; + print_text_with_coordinates( + Text::new(leader_key_text) + .color_range(2, ..8) + .color_range(3, 9..primary_modifier_key_text_len + 10) + .color_range( + 0, + primary_modifier_key_text_len + 11 + ..primary_modifier_key_text_len + 12 + secondary_modifier_key_text_len, + ), + left_padding, + top_coordinates, + None, + None, + ) + }; + } + fn render_help_text_setup_wizard(&self, rows: usize, cols: usize) { + let full_help_text = + "Help: <↓↑> - navigate, - apply & save, - change leaders, - close"; + let short_help_text = "Help: <↓↑> / / / "; + if cols >= full_help_text.chars().count() { + print_text_with_coordinates( + Text::new(full_help_text) + .color_range(2, 6..10) + .color_range(2, 23..30) + .color_range(2, 47..50) + .color_range(2, 69..74), + 0, + rows, + None, + None, + ); + } else { + print_text_with_coordinates( + Text::new(short_help_text) + .color_range(2, 6..10) + .color_range(2, 13..20) + .color_range(2, 23..26) + .color_range(2, 29..34), + 0, + rows, + None, + None, + ); + } + } + fn render_override_title( + &self, + rows: usize, + cols: usize, + primary_modifier_key_text: &str, + ui_size: usize, + ) { + let widths = self.main_screen_widths(primary_modifier_key_text); + if cols >= widths.0 { + let title_text = "Override keybindings with one of the following presets:"; + let left_padding = cols.saturating_sub(widths.0) / 2; + print_text_with_coordinates( + Text::new(title_text).color_range(2, ..), + left_padding, + (rows.saturating_sub(ui_size) / 2) + 1, + None, + None, + ); + } else { + let title_text = "Override keybindings:"; + let left_padding = if cols >= widths.1 { + cols.saturating_sub(widths.1) / 2 + } else { + cols.saturating_sub(widths.2) / 2 + }; + print_text_with_coordinates( + Text::new(title_text).color_range(2, ..), + left_padding, + (rows.saturating_sub(ui_size) / 2) + 1, + None, + None, + ); + } + } + fn render_help_text_main(&self, rows: usize, cols: usize) { + let full_help_text = "Help: <↓↑> - navigate, - apply, - apply & save, - leaders, - close"; + let short_help_text = "Help: <↓↑> / / / / "; + if cols >= full_help_text.chars().count() { + print_text_with_coordinates( + Text::new(full_help_text) + .color_range(2, 6..10) + .color_range(2, 23..30) + .color_range(2, 40..45) + .color_range(2, 62..65) + .color_range(2, 77..82), + 0, + rows, + None, + None, + ); + } else { + print_text_with_coordinates( + Text::new(short_help_text) + .color_range(2, 6..10) + .color_range(2, 13..20) + .color_range(2, 23..28) + .color_range(2, 31..34) + .color_range(2, 37..42), + 0, + rows, + None, + None, + ); + } + } + fn warning_text(&self, max_width: usize) -> Option { + 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) + } +} diff --git a/default-plugins/configuration/src/rebind_leaders_screen.rs b/default-plugins/configuration/src/rebind_leaders_screen.rs new file mode 100644 index 00000000..cc385983 --- /dev/null +++ b/default-plugins/configuration/src/rebind_leaders_screen.rs @@ -0,0 +1,1262 @@ +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, + primary_modifier: BTreeSet, + secondary_modifier: BTreeSet, + latest_mode_info: Option, + notification: Option, + 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) -> 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, BTreeSet) { + ( + 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, + ) { + 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 { + 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() { + "".to_owned() + } else { + self.primary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .join("-") + } + } + fn secondary_modifier_text(&self) -> String { + if self.secondary_modifier.is_empty() { + "".to_owned() + } else { + self.secondary_modifier + .iter() + .map(|m| m.to_string()) + .collect::>() + .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, - select, - apply, - save, - reset, - close"; + let help_text_medium = "Help: <←↓↑→/SPACE> - navigate/select, - apply/save, - reset, - close"; + let help_text_short = "Help: <←↓↑→>// select/ save/ reset/"; + let help_text_minimum = "<←↓↑→>/////"; + 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, - select, - apply to presets in previous screen"; + let help_text_medium = "Help: <←↓↑→> - navigate, - select, - apply"; + let help_text_short = "<←↓↑→/SPACE> - navigate/select, - apply"; + let help_text_minimum = "<←↓↑→>//"; + 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)>, + ) { + 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)>, + 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 { + 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::>() + }) + .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)>, + 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)>, + ) { + 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: &[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)>, + 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 { + 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 { + 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) + } +} diff --git a/default-plugins/configuration/src/ui_components.rs b/default-plugins/configuration/src/ui_components.rs new file mode 100644 index 00000000..3cbdf76c --- /dev/null +++ b/default-plugins/configuration/src/ui_components.rs @@ -0,0 +1,86 @@ +use crate::{Screen, WIDTH_BREAKPOINTS}; +use zellij_tile::prelude::*; + +pub fn top_tab_menu(cols: usize, current_screen: &Screen) { + let first_ribbon_text_long = "Rebind leader keys"; + let second_ribbon_text_long = "Change mode behavior"; + let first_ribbon_text_short = "Rebind keys"; + let second_ribbon_text_short = "Mode behavior"; + let (first_ribbon_is_selected, second_ribbon_is_selected) = match current_screen { + Screen::RebindLeaders(_) => (true, false), + Screen::Presets(_) => (false, true), + }; + let (first_ribbon_text, second_ribbon_text, starting_positions) = if cols + >= first_ribbon_text_long.chars().count() + second_ribbon_text_long.chars().count() + 14 + { + (first_ribbon_text_long, second_ribbon_text_long, (6, 28)) + } else { + (first_ribbon_text_short, second_ribbon_text_short, (6, 21)) + }; + let mut first_ribbon = Text::new(first_ribbon_text); + let mut second_ribbon = Text::new(second_ribbon_text); + if first_ribbon_is_selected { + first_ribbon = first_ribbon.selected(); + } + if second_ribbon_is_selected { + second_ribbon = second_ribbon.selected(); + } + let switch_key = Text::new("").color_range(3, ..); + print_text_with_coordinates(switch_key, 0, 0, None, None); + print_ribbon_with_coordinates(first_ribbon, starting_positions.0, 0, None, None); + print_ribbon_with_coordinates(second_ribbon, starting_positions.1, 0, None, None); +} + +pub fn back_to_presets() { + let esc = Text::new("").color_range(3, ..); + let first_ribbon = Text::new("Back to Presets"); + print_text_with_coordinates(esc, 0, 0, None, None); + print_ribbon_with_coordinates(first_ribbon, 6, 0, None, None); +} + +pub fn info_line( + rows: usize, + cols: usize, + ui_size: usize, + notification: &Option, + warning_text: &Option, + widths: Option<(usize, usize, usize)>, +) { + let top_coordinates = if rows > 14 { + (rows.saturating_sub(ui_size) / 2) + 14 + } else { + (rows.saturating_sub(ui_size) / 2) + 10 + }; + let left_padding = if let Some(widths) = widths { + if cols >= widths.0 { + cols.saturating_sub(widths.0) / 2 + } else if cols >= widths.1 { + cols.saturating_sub(widths.1) / 2 + } else { + cols.saturating_sub(widths.2) / 2 + } + } else { + if cols >= WIDTH_BREAKPOINTS.0 { + cols.saturating_sub(WIDTH_BREAKPOINTS.0) / 2 + } else { + cols.saturating_sub(WIDTH_BREAKPOINTS.1) / 2 + } + }; + if let Some(notification) = ¬ification { + print_text_with_coordinates( + Text::new(notification).color_range(3, ..), + left_padding, + top_coordinates, + None, + None, + ); + } else if let Some(warning_text) = warning_text { + print_text_with_coordinates( + Text::new(warning_text).color_range(3, ..), + left_padding, + top_coordinates, + None, + None, + ); + } +} diff --git a/default-plugins/status-bar/src/one_line_ui.rs b/default-plugins/status-bar/src/one_line_ui.rs index 571cdfa6..2db13d78 100644 --- a/default-plugins/status-bar/src/one_line_ui.rs +++ b/default-plugins/status-bar/src/one_line_ui.rs @@ -696,7 +696,7 @@ fn secondary_keybinds(help: &ModeInfo, tab_info: Option<&TabInfo>, max_len: usiz let move_focus_left_action_key = action_key(binds, &[Action::MoveFocusOrTab(Direction::Left)]); let move_focus_left_key = move_focus_left_action_key .iter() - .find(|k| k.is_key_with_alt_modifier(BareKey::Left)) + .find(|k| k.bare_key == BareKey::Left) .or_else(|| move_focus_left_action_key.iter().next()); if let Some(move_focus_left_key) = move_focus_left_key { move_focus_shortcuts.push(move_focus_left_key.clone()); @@ -705,7 +705,7 @@ fn secondary_keybinds(help: &ModeInfo, tab_info: Option<&TabInfo>, max_len: usiz let move_focus_left_action_key = action_key(binds, &[Action::MoveFocus(Direction::Down)]); let move_focus_left_key = move_focus_left_action_key .iter() - .find(|k| k.is_key_with_alt_modifier(BareKey::Down)) + .find(|k| k.bare_key == BareKey::Down) .or_else(|| move_focus_left_action_key.iter().next()); if let Some(move_focus_left_key) = move_focus_left_key { move_focus_shortcuts.push(move_focus_left_key.clone()); @@ -714,7 +714,7 @@ fn secondary_keybinds(help: &ModeInfo, tab_info: Option<&TabInfo>, max_len: usiz let move_focus_left_action_key = action_key(binds, &[Action::MoveFocus(Direction::Up)]); let move_focus_left_key = move_focus_left_action_key .iter() - .find(|k| k.is_key_with_alt_modifier(BareKey::Up)) + .find(|k| k.bare_key == BareKey::Up) .or_else(|| move_focus_left_action_key.iter().next()); if let Some(move_focus_left_key) = move_focus_left_key { move_focus_shortcuts.push(move_focus_left_key.clone()); @@ -723,7 +723,7 @@ fn secondary_keybinds(help: &ModeInfo, tab_info: Option<&TabInfo>, max_len: usiz let move_focus_left_action_key = action_key(binds, &[Action::MoveFocusOrTab(Direction::Right)]); let move_focus_left_key = move_focus_left_action_key .iter() - .find(|k| k.is_key_with_alt_modifier(BareKey::Right)) + .find(|k| k.bare_key == BareKey::Right) .or_else(|| move_focus_left_action_key.iter().next()); if let Some(move_focus_left_key) = move_focus_left_key { move_focus_shortcuts.push(move_focus_left_key.clone());