diff options
author | Aram Drevekenin <aram@poor.dev> | 2023-11-05 13:24:33 +0100 |
---|---|---|
committer | Aram Drevekenin <aram@poor.dev> | 2023-11-05 13:24:33 +0100 |
commit | cc9dd35ba8bccada9f63ee8d4fbd3051b70b204d (patch) | |
tree | 4ed2de7f659aa1dcad8e7e6c052d396c5d900375 | |
parent | 3ffd9d2a09adb66b428532cfea90ec9974f8f49b (diff) |
change session name from the session-manager
-rw-r--r-- | default-plugins/session-manager/src/main.rs | 86 | ||||
-rw-r--r-- | default-plugins/session-manager/src/resurrectable_sessions.rs | 3 | ||||
-rw-r--r-- | default-plugins/session-manager/src/session_list.rs | 6 | ||||
-rw-r--r-- | default-plugins/session-manager/src/ui/components.rs | 51 | ||||
-rw-r--r-- | zellij-server/src/plugins/zellij_exports.rs | 10 | ||||
-rw-r--r-- | zellij-tile/src/shim.rs | 8 | ||||
-rw-r--r-- | zellij-utils/assets/prost/api.plugin_command.rs | 7 | ||||
-rw-r--r-- | zellij-utils/src/data.rs | 1 | ||||
-rw-r--r-- | zellij-utils/src/plugin_api/plugin_command.proto | 2 | ||||
-rw-r--r-- | zellij-utils/src/plugin_api/plugin_command.rs | 10 |
10 files changed, 171 insertions, 13 deletions
diff --git a/default-plugins/session-manager/src/main.rs b/default-plugins/session-manager/src/main.rs index 7e39307d9..ce54ce559 100644 --- a/default-plugins/session-manager/src/main.rs +++ b/default-plugins/session-manager/src/main.rs @@ -7,7 +7,7 @@ use std::collections::BTreeMap; use ui::{ components::{ - render_controls_line, render_new_session_line, render_prompt, render_resurrection_toggle, + render_controls_line, render_error, render_renaming_session_screen, render_new_session_line, render_prompt, 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,26 @@ 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 +299,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..79df37a9b 100644 --- a/default-plugins/session-manager/src/resurrectable_sessions.rs +++ b/default-plugins/session-manager/src/resurrectable_sessions.rs @@ -308,6 +308,9 @@ 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..cf822ac4e 100644 --- a/default-plugins/session-manager/src/session_list.rs +++ b/default-plugins/session-manager/src/session_list.rs @@ -314,6 +314,12 @@ 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}"); } } diff --git a/zellij-server/src/plugins/zellij_exports.rs b/zellij-server/src/plugins/zellij_exports.rs index 38b89ceac..2a2de5e09 100644 --- a/zellij-server/src/plugins/zellij_exports.rs +++ b/zellij-server/src/plugins/zellij_exports.rs @@ -237,6 +237,9 @@ fn host_run_plugin_command(env: FunctionEnvMut<ForeignFunctionEnv>) { PluginCommand::OpenCommandPaneInPlace(command_to_run) => { open_command_pane_in_place(env, command_to_run) }, + PluginCommand::RenameSession(new_session_name) => { + rename_session(env, new_session_name) + }, }, (PermissionStatus::Denied, permission) => { log::error!( @@ -1188,6 +1191,12 @@ fn rename_tab(env: &ForeignFunctionEnv, tab_index: u32, new_name: &str) { apply_action!(rename_tab_action, error_msg, env); } +fn rename_session(env: &ForeignFunctionEnv, new_session_name: String) { + let error_msg = || format!("failed to rename session in plugin {}", env.plugin_env.name()); + let action = Action::RenameSession(new_session_name); + apply_action!(action, error_msg, env); +} + // Custom panic handler for plugins. // // This is called when a panic occurs in a plugin. Since most panics will likely originate in the @@ -1315,6 +1324,7 @@ fn check_command_permission( | PluginCommand::SwitchSession(..) | PluginCommand::DeleteDeadSession(..) | PluginCommand::DeleteAllDeadSessions + | PluginCommand::RenameSession(..) | PluginCommand::RenameTab(..) => PermissionType::ChangeApplicationState, _ => return (PermissionStatus::Granted, None), }; diff --git a/zellij-tile/src/shim.rs b/zellij-tile/src/shim.rs index eb898b4fc..8f2b297a3 100644 --- a/zellij-tile/src/shim.rs +++ b/zellij-tile/src/shim.rs @@ -682,6 +682,14 @@ pub fn delete_all_dead_sessions() { unsafe { host_run_plugin_command() }; } +/// Rename the current session +pub fn rename_session(name: &str) { + let plugin_command = PluginCommand::RenameSession(name.to_owned()); + let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); + object_to_stdout(&protobuf_plugin_command.encode_to_vec()); + unsafe { host_run_plugin_command() }; +} + // Utility Functions #[allow(unused)] diff --git a/zellij-utils/assets/prost/api.plugin_command.rs b/zellij-utils/assets/prost/api.plugin_command.rs index f0d2fe02f..0dd5f6814 100644 --- a/zellij-utils/assets/prost/api.plugin_command.rs +++ b/zellij-utils/assets/prost/api.plugin_command.rs @@ -5,7 +5,7 @@ pub struct PluginCommand { pub name: i32, #[prost( oneof = "plugin_command::Payload", - tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45" + tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46" )] pub payload: ::core::option::Option<plugin_command::Payload>, } @@ -102,6 +102,8 @@ pub mod plugin_command { WebRequestPayload(super::WebRequestPayload), #[prost(string, tag = "45")] DeleteDeadSessionPayload(::prost::alloc::string::String), + #[prost(string, tag = "46")] + RenameSessionPayload(::prost::alloc::string::String), } } #[allow(clippy::derive_partial_eq_without_eq)] @@ -315,6 +317,7 @@ pub enum CommandName { WebRequest = 72, DeleteDeadSession = 73, DeleteAllDeadSessions = 74, + RenameSession = 75, } impl CommandName { /// String value of the enum field names used in the ProtoBuf definition. @@ -398,6 +401,7 @@ impl CommandName { CommandName::WebRequest => "WebRequest", CommandName::DeleteDeadSession => "DeleteDeadSession", CommandName::DeleteAllDeadSessions => "DeleteAllDeadSessions", + CommandName::RenameSession => "RenameSession", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -478,6 +482,7 @@ impl CommandName { "WebRequest" => Some(Self::WebRequest), "DeleteDeadSession" => Some(Self::DeleteDeadSession), "DeleteAllDeadSessions" => Some(Self::DeleteAllDeadSessions), + "RenameSession" => Some(Self::RenameSession), _ => None, } } diff --git a/zellij-utils/src/data.rs b/zellij-utils/src/data.rs index 82daf118d..bed6f4747 100644 --- a/zellij-utils/src/data.rs +++ b/zellij-utils/src/data.rs @@ -1104,4 +1104,5 @@ pub enum PluginCommand { Vec<u8>, // body BTreeMap<String, String>, // context ), + RenameSession(String), // String -> new session name } diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto index 0b950ff0e..53994a88c 100644 --- a/zellij-utils/src/plugin_api/plugin_command.proto +++ b/zellij-utils/src/plugin_api/plugin_command.proto @@ -86,6 +86,7 @@ enum CommandName { WebRequest = 72; DeleteDeadSession = 73; DeleteAllDeadSessions = 74; + RenameSession = 75; } message PluginCommand { @@ -135,6 +136,7 @@ message PluginCommand { RunCommandPayload run_command_payload = 43; WebRequestPayload web_request_payload = 44; string delete_dead_session_payload = 45; + string rename_session_payload = 46; } } diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs index 6b70b18eb..ed476687c 100644 --- a/zellij-utils/src/plugin_api/plugin_command.rs +++ b/zellij-utils/src/plugin_api/plugin_command.rs @@ -635,6 +635,12 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand { _ => Err("Mismatched payload for DeleteDeadSession"), }, Some(CommandName::DeleteAllDeadSessions) => Ok(PluginCommand::DeleteAllDeadSessions), + Some(CommandName::RenameSession) => match protobuf_plugin_command.payload { + Some(Payload::RenameSessionPayload(new_session_name)) => { + Ok(PluginCommand::RenameSession(new_session_name)) + }, + _ => Err("Mismatched payload for RenameSession"), + }, None => Err("Unrecognized plugin command"), } } @@ -1059,6 +1065,10 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand { name: CommandName::DeleteAllDeadSessions as i32, payload: None, }), + PluginCommand::RenameSession(new_session_name) => Ok(ProtobufPluginCommand { + name: CommandName::RenameSession as i32, + payload: Some(Payload::RenameSessionPayload(new_session_name)), + }), } } } |