diff options
author | Aram Drevekenin <aram@poor.dev> | 2023-11-05 15:32:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-05 15:32:05 +0100 |
commit | 28a165a969a9e1ee9f1fe66e4d63134b895b2ef7 (patch) | |
tree | 678ec1cd9d536d9cb7fcdb071e27cf12caf43afb /default-plugins | |
parent | 9eb9734bcca3cb0dcdff592da4d7a536d860c363 (diff) |
feat(ux): allow renaming sessions (#2903)
* change session name through the cli
* change session name from the session-manager
* style(fmt): rustfmt
Diffstat (limited to 'default-plugins')
4 files changed, 143 insertions, 13 deletions
diff --git a/default-plugins/session-manager/src/main.rs b/default-plugins/session-manager/src/main.rs index 7e39307d9..8f70cc295 100644 --- a/default-plugins/session-manager/src/main.rs +++ b/default-plugins/session-manager/src/main.rs @@ -7,8 +7,8 @@ use std::collections::BTreeMap; use ui::{ components::{ - render_controls_line, render_new_session_line, render_prompt, render_resurrection_toggle, - Colors, + render_controls_line, render_error, render_new_session_line, render_prompt, + render_renaming_session_screen, render_resurrection_toggle, Colors, }, SessionUiInfo, }; @@ -23,6 +23,8 @@ struct State { resurrectable_sessions: ResurrectableSessions, search_term: String, new_session_name: Option<String>, + renaming_session_name: Option<String>, + error: Option<String>, browsing_resurrection_sessions: bool, colors: Colors, } @@ -67,6 +69,9 @@ impl ZellijPlugin for State { if self.browsing_resurrection_sessions { self.resurrectable_sessions.render(rows, cols); return; + } else if let Some(new_session_name) = self.renaming_session_name.as_ref() { + render_renaming_session_screen(&new_session_name, rows, cols); + return; } render_resurrection_toggle(cols, false); render_prompt( @@ -87,7 +92,11 @@ impl ZellijPlugin for State { self.sessions.is_searching, self.colors, ); - render_controls_line(self.sessions.is_searching, rows, cols, self.colors); + if let Some(error) = self.error.as_ref() { + render_error(&error, rows, cols); + } else { + render_controls_line(self.sessions.is_searching, rows, cols, self.colors); + } } } @@ -96,6 +105,10 @@ impl State { self.sessions.reset_selected_index(); } fn handle_key(&mut self, key: Key) -> bool { + if self.error.is_some() { + self.error = None; + return true; + } let mut should_render = false; if let Key::Right = key { if self.new_session_name.is_none() { @@ -110,14 +123,14 @@ impl State { } else if let Key::Down = key { if self.browsing_resurrection_sessions { self.resurrectable_sessions.move_selection_down(); - } else if self.new_session_name.is_none() { + } else if self.new_session_name.is_none() && self.renaming_session_name.is_none() { self.sessions.move_selection_down(); } should_render = true; } else if let Key::Up = key { if self.browsing_resurrection_sessions { self.resurrectable_sessions.move_selection_up(); - } else if self.new_session_name.is_none() { + } else if self.new_session_name.is_none() && self.renaming_session_name.is_none() { self.sessions.move_selection_up(); } should_render = true; @@ -126,6 +139,8 @@ impl State { self.handle_selection(); } else if let Some(new_session_name) = self.new_session_name.as_mut() { new_session_name.push(character); + } else if let Some(renaming_session_name) = self.renaming_session_name.as_mut() { + renaming_session_name.push(character); } else if self.browsing_resurrection_sessions { self.resurrectable_sessions.handle_character(character); } else { @@ -141,6 +156,12 @@ impl State { } else { new_session_name.pop(); } + } else if let Some(renaming_session_name) = self.renaming_session_name.as_mut() { + if renaming_session_name.is_empty() { + self.renaming_session_name = None; + } else { + renaming_session_name.pop(); + } } else if self.browsing_resurrection_sessions { self.resurrectable_sessions.handle_backspace(); } else { @@ -150,7 +171,7 @@ impl State { } should_render = true; } else if let Key::Ctrl('w') = key { - if self.sessions.is_searching { + if self.sessions.is_searching || self.browsing_resurrection_sessions { // no-op } else if self.new_session_name.is_some() { self.new_session_name = None; @@ -158,6 +179,15 @@ impl State { self.new_session_name = Some(String::new()); } should_render = true; + } else if let Key::Ctrl('r') = key { + if self.sessions.is_searching || self.browsing_resurrection_sessions { + // no-op + } else if self.renaming_session_name.is_some() { + self.renaming_session_name = None; + } else { + self.renaming_session_name = Some(String::new()); + } + should_render = true; } else if let Key::Ctrl('c') = key { if let Some(new_session_name) = self.new_session_name.as_mut() { if new_session_name.is_empty() { @@ -165,6 +195,12 @@ impl State { } else { new_session_name.clear() } + } else if let Some(renaming_session_name) = self.renaming_session_name.as_mut() { + if renaming_session_name.is_empty() { + self.renaming_session_name = None; + } else { + renaming_session_name.clear() + } } else if !self.search_term.is_empty() { self.search_term.clear(); self.sessions @@ -190,7 +226,15 @@ impl State { should_render = true; } } else if let Key::Esc = key { - hide_self(); + if self.renaming_session_name.is_some() { + self.renaming_session_name = None; + should_render = true; + } else if self.new_session_name.is_some() { + self.new_session_name = None; + should_render = true; + } else { + hide_self(); + } } should_render } @@ -210,6 +254,29 @@ impl State { } else { switch_session(Some(new_session_name)); } + } else if let Some(renaming_session_name) = &self.renaming_session_name.take() { + if renaming_session_name.is_empty() { + // TODO: implement these, then implement the error UI, then implement the renaming + // session screen, then test it + self.show_error("New name must not be empty."); + return; // s that we don't hide self + } else if self.session_name.as_ref() == Some(renaming_session_name) { + // noop - we're already called that! + return; // s that we don't hide self + } else if self.sessions.has_session(&renaming_session_name) { + self.show_error("A session by this name already exists."); + return; // s that we don't hide self + } else if self + .resurrectable_sessions + .has_session(&renaming_session_name) + { + self.show_error("A resurrectable session by this name already exists."); + return; // s that we don't hide self + } else { + self.update_current_session_name_in_ui(&renaming_session_name); + rename_session(&renaming_session_name); + return; // s that we don't hide self + } } else if let Some(selected_session_name) = self.sessions.get_selected_session_name() { let selected_tab = self.sessions.get_selected_tab_position(); let selected_pane = self.sessions.get_selected_pane_id(); @@ -235,6 +302,16 @@ impl State { .update_search_term(&self.search_term, &self.colors); hide_self(); } + fn show_error(&mut self, error_text: &str) { + self.error = Some(error_text.to_owned()); + } + fn update_current_session_name_in_ui(&mut self, new_name: &str) { + if let Some(old_session_name) = self.session_name.as_ref() { + self.sessions + .update_session_name(&old_session_name, new_name); + } + self.session_name = Some(new_name.to_owned()); + } fn update_session_infos(&mut self, session_infos: Vec<SessionInfo>) { let session_infos: Vec<SessionUiInfo> = session_infos .iter() diff --git a/default-plugins/session-manager/src/resurrectable_sessions.rs b/default-plugins/session-manager/src/resurrectable_sessions.rs index beed254fd..dfbb86f0d 100644 --- a/default-plugins/session-manager/src/resurrectable_sessions.rs +++ b/default-plugins/session-manager/src/resurrectable_sessions.rs @@ -308,6 +308,11 @@ impl ResurrectableSessions { self.search_term.pop(); self.update_search_term(); } + pub fn has_session(&self, session_name: &str) -> bool { + self.all_resurrectable_sessions + .iter() + .any(|s| s.0 == session_name) + } fn update_search_term(&mut self) { let mut matches = vec![]; let matcher = SkimMatcherV2::default().use_cache(true); diff --git a/default-plugins/session-manager/src/session_list.rs b/default-plugins/session-manager/src/session_list.rs index 788d324f7..fa63571e8 100644 --- a/default-plugins/session-manager/src/session_list.rs +++ b/default-plugins/session-manager/src/session_list.rs @@ -314,6 +314,15 @@ impl SessionList { pub fn reset_selected_index(&mut self) { self.selected_index.reset(); } + pub fn has_session(&self, session_name: &str) -> bool { + self.session_ui_infos.iter().any(|s| s.name == session_name) + } + pub fn update_session_name(&mut self, old_name: &str, new_name: &str) { + self.session_ui_infos + .iter_mut() + .find(|s| s.name == old_name) + .map(|s| s.name = new_name.to_owned()); + } } #[derive(Debug, Clone, Default)] diff --git a/default-plugins/session-manager/src/ui/components.rs b/default-plugins/session-manager/src/ui/components.rs index be3da41df..4d9839c0f 100644 --- a/default-plugins/session-manager/src/ui/components.rs +++ b/default-plugins/session-manager/src/ui/components.rs @@ -558,29 +558,68 @@ pub fn render_new_session_line(session_name: &Option<String>, is_searching: bool } } +pub fn render_error(error_text: &str, rows: usize, columns: usize) { + print_text_with_coordinates( + Text::new(format!("Error: {}", error_text)).color_range(3, ..), + 0, + rows, + Some(columns), + None, + ); +} + +pub fn render_renaming_session_screen(new_session_name: &str, rows: usize, columns: usize) { + if rows == 0 || columns == 0 { + return; + } + let prompt_text = "NEW NAME FOR CURRENT SESSION"; + let new_session_name = format!("{}_", new_session_name); + let prompt_y_location = (rows / 2).saturating_sub(1); + let session_name_y_location = (rows / 2) + 1; + let prompt_x_location = columns.saturating_sub(prompt_text.chars().count()) / 2; + let session_name_x_location = columns.saturating_sub(new_session_name.chars().count()) / 2; + print_text_with_coordinates( + Text::new(prompt_text).color_range(0, ..), + prompt_x_location, + prompt_y_location, + None, + None, + ); + print_text_with_coordinates( + Text::new(new_session_name).color_range(3, ..), + session_name_x_location, + session_name_y_location, + None, + None, + ); +} + pub fn render_controls_line(is_searching: bool, row: usize, max_cols: usize, colors: Colors) { let (arrows, navigate) = if is_searching { (colors.magenta("<↓↑>"), colors.bold("Navigate")) } else { (colors.magenta("<←↓↑→>"), colors.bold("Navigate and Expand")) }; + let rename = colors.magenta("<Ctrl r>"); + let rename_text = colors.bold("Rename session"); let enter = colors.magenta("<ENTER>"); let select = colors.bold("Switch to selected"); let esc = colors.magenta("<ESC>"); let to_hide = colors.bold("Hide"); - if max_cols >= 80 { + if max_cols >= 104 { print!( - "\u{1b}[m\u{1b}[{row}HHelp: {arrows} - {navigate}, {enter} - {select}, {esc} - {to_hide}" + "\u{1b}[m\u{1b}[{row}HHelp: {arrows} - {navigate}, {enter} - {select}, {rename} - {rename_text}, {esc} - {to_hide}" ); - } else if max_cols >= 57 { + } else if max_cols >= 73 { let navigate = colors.bold("Navigate"); let select = colors.bold("Switch"); + let rename_text = colors.bold("Rename"); print!( - "\u{1b}[m\u{1b}[{row}HHelp: {arrows} - {navigate}, {enter} - {select}, {esc} - {to_hide}" + "\u{1b}[m\u{1b}[{row}HHelp: {arrows} - {navigate}, {enter} - {select}, {rename} - {rename_text}, {esc} - {to_hide}" ); - } else if max_cols >= 20 { - print!("\u{1b}[m\u{1b}[{row}H{arrows}/{enter}/{esc}"); + } else if max_cols >= 28 { + print!("\u{1b}[m\u{1b}[{row}H{arrows}/{enter}/{rename}/{esc}"); } } |