mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-22 13:02:12 +03:00
feat(ux): allow renaming sessions (#2903)
* change session name through the cli * change session name from the session-manager * style(fmt): rustfmt
This commit is contained in:
parent
9eb9734bcc
commit
28a165a969
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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)]
|
||||
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,10 @@ pub fn start_cli_client(os_input: Box<dyn ClientOsApi>, session_name: &str, acti
|
||||
log_lines.iter().for_each(|line| println!("{line}"));
|
||||
process::exit(0);
|
||||
},
|
||||
Some((ServerToClientMsg::LogError(log_lines), _)) => {
|
||||
log_lines.iter().for_each(|line| eprintln!("{line}"));
|
||||
process::exit(2);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ pub(crate) enum ClientInstruction {
|
||||
StartedParsingStdinQuery,
|
||||
DoneParsingStdinQuery,
|
||||
Log(Vec<String>),
|
||||
LogError(Vec<String>),
|
||||
SwitchSession(ConnectToSession),
|
||||
SetSynchronizedOutput(Option<SyncOutput>),
|
||||
}
|
||||
@ -62,6 +63,7 @@ impl From<ServerToClientMsg> for ClientInstruction {
|
||||
ServerToClientMsg::Connected => ClientInstruction::Connected,
|
||||
ServerToClientMsg::ActiveClients(clients) => ClientInstruction::ActiveClients(clients),
|
||||
ServerToClientMsg::Log(log_lines) => ClientInstruction::Log(log_lines),
|
||||
ServerToClientMsg::LogError(log_lines) => ClientInstruction::LogError(log_lines),
|
||||
ServerToClientMsg::SwitchSession(connect_to_session) => {
|
||||
ClientInstruction::SwitchSession(connect_to_session)
|
||||
},
|
||||
@ -80,6 +82,7 @@ impl From<&ClientInstruction> for ClientContext {
|
||||
ClientInstruction::Connected => ClientContext::Connected,
|
||||
ClientInstruction::ActiveClients(_) => ClientContext::ActiveClients,
|
||||
ClientInstruction::Log(_) => ClientContext::Log,
|
||||
ClientInstruction::LogError(_) => ClientContext::LogError,
|
||||
ClientInstruction::StartedParsingStdinQuery => ClientContext::StartedParsingStdinQuery,
|
||||
ClientInstruction::DoneParsingStdinQuery => ClientContext::DoneParsingStdinQuery,
|
||||
ClientInstruction::SwitchSession(..) => ClientContext::SwitchSession,
|
||||
@ -473,6 +476,11 @@ pub fn start_client(
|
||||
log::info!("{line}");
|
||||
}
|
||||
},
|
||||
ClientInstruction::LogError(lines_to_log) => {
|
||||
for line in lines_to_log {
|
||||
log::error!("{line}");
|
||||
}
|
||||
},
|
||||
ClientInstruction::SwitchSession(connect_to_session) => {
|
||||
reconnect_to_session = Some(connect_to_session);
|
||||
os_input.send_to_server(ClientToServerMsg::ClientExited);
|
||||
|
@ -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,17 @@ 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 +1329,7 @@ fn check_command_permission(
|
||||
| PluginCommand::SwitchSession(..)
|
||||
| PluginCommand::DeleteDeadSession(..)
|
||||
| PluginCommand::DeleteAllDeadSessions
|
||||
| PluginCommand::RenameSession(..)
|
||||
| PluginCommand::RenameTab(..) => PermissionType::ChangeApplicationState,
|
||||
_ => return (PermissionStatus::Granted, None),
|
||||
};
|
||||
|
@ -784,6 +784,11 @@ pub(crate) fn route_action(
|
||||
.send_to_screen(ScreenInstruction::BreakPaneLeft(client_id))
|
||||
.with_context(err_context)?;
|
||||
},
|
||||
Action::RenameSession(name) => {
|
||||
senders
|
||||
.send_to_screen(ScreenInstruction::RenameSession(name, client_id))
|
||||
.with_context(err_context)?;
|
||||
},
|
||||
}
|
||||
Ok(should_break)
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ use zellij_utils::input::command::RunCommand;
|
||||
use zellij_utils::input::options::Clipboard;
|
||||
use zellij_utils::pane_size::{Size, SizeInPixels};
|
||||
use zellij_utils::{
|
||||
consts::{session_info_folder_for_session, ZELLIJ_SOCK_DIR},
|
||||
envs::set_session_name,
|
||||
input::command::TerminalAction,
|
||||
input::layout::{
|
||||
FloatingPaneLayout, Layout, PluginUserConfiguration, Run, RunPlugin, RunPluginLocation,
|
||||
@ -314,6 +316,7 @@ pub enum ScreenInstruction {
|
||||
ClientTabIndexOrPaneId,
|
||||
),
|
||||
DumpLayoutToHd,
|
||||
RenameSession(String, ClientId), // String -> new name
|
||||
}
|
||||
|
||||
impl From<&ScreenInstruction> for ScreenContext {
|
||||
@ -492,6 +495,7 @@ impl From<&ScreenInstruction> for ScreenContext {
|
||||
ScreenInstruction::ReplacePane(..) => ScreenContext::ReplacePane,
|
||||
ScreenInstruction::NewInPlacePluginPane(..) => ScreenContext::NewInPlacePluginPane,
|
||||
ScreenInstruction::DumpLayoutToHd => ScreenContext::DumpLayoutToHd,
|
||||
ScreenInstruction::RenameSession(..) => ScreenContext::RenameSession,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1520,7 +1524,10 @@ impl Screen {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn change_mode(&mut self, mode_info: ModeInfo, client_id: ClientId) -> Result<()> {
|
||||
pub fn change_mode(&mut self, mut mode_info: ModeInfo, client_id: ClientId) -> Result<()> {
|
||||
if mode_info.session_name.as_ref() != Some(&self.session_name) {
|
||||
mode_info.session_name = Some(self.session_name.clone());
|
||||
}
|
||||
let previous_mode = self
|
||||
.mode_info
|
||||
.get(&client_id)
|
||||
@ -3471,6 +3478,69 @@ pub(crate) fn screen_thread_main(
|
||||
screen.dump_layout_to_hd()?;
|
||||
}
|
||||
},
|
||||
ScreenInstruction::RenameSession(name, client_id) => {
|
||||
if screen.session_infos_on_machine.contains_key(&name) {
|
||||
let error_text = "A session by this name already exists.";
|
||||
log::error!("{}", error_text);
|
||||
if let Some(os_input) = &mut screen.bus.os_input {
|
||||
let _ = os_input.send_to_client(
|
||||
client_id,
|
||||
ServerToClientMsg::LogError(vec![error_text.to_owned()]),
|
||||
);
|
||||
}
|
||||
} else if screen.resurrectable_sessions.contains_key(&name) {
|
||||
let error_text =
|
||||
"A resurrectable session by this name exists, cannot use this name.";
|
||||
log::error!("{}", error_text);
|
||||
if let Some(os_input) = &mut screen.bus.os_input {
|
||||
let _ = os_input.send_to_client(
|
||||
client_id,
|
||||
ServerToClientMsg::LogError(vec![error_text.to_owned()]),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let err_context = || format!("Failed to rename session");
|
||||
let old_session_name = screen.session_name.clone();
|
||||
|
||||
// update state
|
||||
screen.session_name = name.clone();
|
||||
screen.default_mode_info.session_name = Some(name.clone());
|
||||
for (_client_id, mut mode_info) in screen.mode_info.iter_mut() {
|
||||
mode_info.session_name = Some(name.clone());
|
||||
}
|
||||
for (_, tab) in screen.tabs.iter_mut() {
|
||||
tab.rename_session(name.clone()).with_context(err_context)?;
|
||||
}
|
||||
|
||||
// rename socket file
|
||||
let old_socket_file_path = ZELLIJ_SOCK_DIR.join(&old_session_name);
|
||||
let new_socket_file_path = ZELLIJ_SOCK_DIR.join(&name);
|
||||
if let Err(e) = std::fs::rename(old_socket_file_path, new_socket_file_path) {
|
||||
log::error!("Failed to rename ipc socket: {:?}", e);
|
||||
}
|
||||
|
||||
// rename session_info folder (TODO: make this atomic, right now there is a
|
||||
// chance background_jobs will re-create this folder before it knows the
|
||||
// session was renamed)
|
||||
let old_session_info_folder =
|
||||
session_info_folder_for_session(&old_session_name);
|
||||
let new_session_info_folder = session_info_folder_for_session(&name);
|
||||
if let Err(e) =
|
||||
std::fs::rename(old_session_info_folder, new_session_info_folder)
|
||||
{
|
||||
log::error!("Failed to rename session_info folder: {:?}", e);
|
||||
}
|
||||
|
||||
// report
|
||||
screen
|
||||
.log_and_report_session_state()
|
||||
.with_context(err_context)?;
|
||||
|
||||
// set the env variable
|
||||
set_session_name(name);
|
||||
}
|
||||
screen.unblock_input()?;
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -838,6 +838,16 @@ impl Tab {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn rename_session(&mut self, new_session_name: String) -> Result<()> {
|
||||
{
|
||||
let mode_infos = &mut self.mode_info.borrow_mut();
|
||||
for (_client_id, mut mode_info) in mode_infos.iter_mut() {
|
||||
mode_info.session_name = Some(new_session_name.clone());
|
||||
}
|
||||
self.default_mode_info.session_name = Some(new_session_name);
|
||||
}
|
||||
self.update_input_modes()
|
||||
}
|
||||
pub fn update_input_modes(&mut self) -> Result<()> {
|
||||
// this updates all plugins with the client's input mode
|
||||
let mode_infos = self.mode_info.borrow();
|
||||
|
@ -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)]
|
||||
|
@ -5,7 +5,7 @@ pub struct Action {
|
||||
pub name: i32,
|
||||
#[prost(
|
||||
oneof = "action::OptionalPayload",
|
||||
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"
|
||||
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"
|
||||
)]
|
||||
pub optional_payload: ::core::option::Option<action::OptionalPayload>,
|
||||
}
|
||||
@ -100,6 +100,8 @@ pub mod action {
|
||||
RenamePluginPanePayload(super::IdAndName),
|
||||
#[prost(message, tag = "44")]
|
||||
RenameTabPayload(super::IdAndName),
|
||||
#[prost(string, tag = "45")]
|
||||
RenameSessionPayload(::prost::alloc::string::String),
|
||||
}
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
@ -400,6 +402,7 @@ pub enum ActionName {
|
||||
BreakPane = 77,
|
||||
BreakPaneRight = 78,
|
||||
BreakPaneLeft = 79,
|
||||
RenameSession = 80,
|
||||
}
|
||||
impl ActionName {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
@ -488,6 +491,7 @@ impl ActionName {
|
||||
ActionName::BreakPane => "BreakPane",
|
||||
ActionName::BreakPaneRight => "BreakPaneRight",
|
||||
ActionName::BreakPaneLeft => "BreakPaneLeft",
|
||||
ActionName::RenameSession => "RenameSession",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
@ -573,6 +577,7 @@ impl ActionName {
|
||||
"BreakPane" => Some(Self::BreakPane),
|
||||
"BreakPaneRight" => Some(Self::BreakPaneRight),
|
||||
"BreakPaneLeft" => Some(Self::BreakPaneLeft),
|
||||
"RenameSession" => Some(Self::RenameSession),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -527,4 +527,7 @@ pub enum CliAction {
|
||||
#[clap(short, long, value_parser)]
|
||||
configuration: Option<PluginUserConfiguration>,
|
||||
},
|
||||
RenameSession {
|
||||
name: String,
|
||||
},
|
||||
}
|
||||
|
@ -1104,4 +1104,5 @@ pub enum PluginCommand {
|
||||
Vec<u8>, // body
|
||||
BTreeMap<String, String>, // context
|
||||
),
|
||||
RenameSession(String), // String -> new session name
|
||||
}
|
||||
|
@ -347,6 +347,7 @@ pub enum ScreenContext {
|
||||
ReplacePane,
|
||||
NewInPlacePluginPane,
|
||||
DumpLayoutToHd,
|
||||
RenameSession,
|
||||
}
|
||||
|
||||
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
|
||||
@ -404,6 +405,7 @@ pub enum ClientContext {
|
||||
Connected,
|
||||
ActiveClients,
|
||||
Log,
|
||||
LogError,
|
||||
OwnClientId,
|
||||
StartedParsingStdinQuery,
|
||||
DoneParsingStdinQuery,
|
||||
|
@ -250,6 +250,7 @@ pub enum Action {
|
||||
BreakPane,
|
||||
BreakPaneRight,
|
||||
BreakPaneLeft,
|
||||
RenameSession(String),
|
||||
}
|
||||
|
||||
impl Action {
|
||||
@ -537,6 +538,7 @@ impl Action {
|
||||
in_place,
|
||||
)])
|
||||
},
|
||||
CliAction::RenameSession { name } => Ok(vec![Action::RenameSession(name)]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ pub enum ServerToClientMsg {
|
||||
Connected,
|
||||
ActiveClients(Vec<ClientId>),
|
||||
Log(Vec<String>),
|
||||
LogError(Vec<String>),
|
||||
SwitchSession(ConnectToSession),
|
||||
}
|
||||
|
||||
|
@ -505,6 +505,7 @@ impl Action {
|
||||
})?;
|
||||
Ok(Action::Search(search_direction))
|
||||
},
|
||||
"RenameSession" => Ok(Action::RenameSession(string)),
|
||||
_ => Err(ConfigError::new_kdl_error(
|
||||
format!("Unsupported action: {}", action_name),
|
||||
action_node.span().offset(),
|
||||
@ -957,6 +958,11 @@ impl TryFrom<(&KdlNode, &Options)> for Action {
|
||||
"BreakPane" => Ok(Action::BreakPane),
|
||||
"BreakPaneRight" => Ok(Action::BreakPaneRight),
|
||||
"BreakPaneLeft" => Ok(Action::BreakPaneLeft),
|
||||
"RenameSession" => parse_kdl_action_char_or_string_arguments!(
|
||||
action_name,
|
||||
action_arguments,
|
||||
kdl_action
|
||||
),
|
||||
_ => Err(ConfigError::new_kdl_error(
|
||||
format!("Unsupported action: {}", action_name).into(),
|
||||
kdl_action.span().offset(),
|
||||
|
@ -51,6 +51,7 @@ message Action {
|
||||
IdAndName rename_terminal_pane_payload = 42;
|
||||
IdAndName rename_plugin_pane_payload = 43;
|
||||
IdAndName rename_tab_payload = 44;
|
||||
string rename_session_payload = 45;
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,6 +222,7 @@ enum ActionName {
|
||||
BreakPane = 77;
|
||||
BreakPaneRight = 78;
|
||||
BreakPaneLeft = 79;
|
||||
RenameSession = 80;
|
||||
}
|
||||
|
||||
message Position {
|
||||
|
@ -626,6 +626,12 @@ impl TryFrom<ProtobufAction> for Action {
|
||||
Some(_) => Err("BreakPaneLeft should not have a payload"),
|
||||
None => Ok(Action::BreakPaneLeft),
|
||||
},
|
||||
Some(ProtobufActionName::RenameSession) => match protobuf_action.optional_payload {
|
||||
Some(OptionalPayload::RenameSessionPayload(name)) => {
|
||||
Ok(Action::RenameSession(name))
|
||||
},
|
||||
_ => Err("Wrong payload for Action::RenameSession"),
|
||||
},
|
||||
_ => Err("Unknown Action"),
|
||||
}
|
||||
}
|
||||
@ -1164,6 +1170,10 @@ impl TryFrom<Action> for ProtobufAction {
|
||||
name: ProtobufActionName::BreakPaneLeft as i32,
|
||||
optional_payload: None,
|
||||
}),
|
||||
Action::RenameSession(session_name) => Ok(ProtobufAction {
|
||||
name: ProtobufActionName::RenameSession as i32,
|
||||
optional_payload: Some(OptionalPayload::RenameSessionPayload(session_name)),
|
||||
}),
|
||||
Action::NoOp
|
||||
| Action::Confirm
|
||||
| Action::NewInPlacePane(..)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user